如何检查DST(夏令时)是否有效,以及偏移是否有效?


154

这是我的JS代码所需要的:

var secDiff = Math.abs(Math.round((utc_date-this.premiere_date)/1000));
this.years = this.calculateUnit(secDiff,(86400*365));
this.days = this.calculateUnit(secDiff-(this.years*(86400*365)),86400);
this.hours = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)),3600);
this.minutes = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)-(this.hours*3600)),60);
this.seconds = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)-(this.hours*3600)-(this.minutes*60)),1);

我想在“ ago”中获取日期时间,但是如果使用了DST,则日期会减少1小时。我不知道如何检查DST是否有效。

我怎么知道夏令时的开始和结束?

Answers:


313

该代码使用的事实是,在标准时间与夏令时(DST)期间getTimezoneOffset返回更大的值。因此,它确定了“标准时间”期间的预期输出,并比较了给定日期的输出是否相同(“标准”)或更少(“ DST”)。

请注意,对于UTC 以西的区域,getTimezoneOffset返回的分钟数为数,通常表示为数小时(因为它们位于UTC之后)。例如,洛杉矶是UTC-8h标准,UTC-7h DST。在12月(冬季,标准时间)返回(正480分钟),而不是。它返回东半球的负数(例如冬天的悉尼,尽管“提前”(UTC + 10h)。getTimezoneOffset480-480-600

Date.prototype.stdTimezoneOffset = function () {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);
    return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
}

Date.prototype.isDstObserved = function () {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
}

var today = new Date();
if (today.isDstObserved()) { 
    alert ("Daylight saving time!");
}

28
我可以验证这在国际上可行。当前没有使用任何形式的DST的时区,其中1月1日和7月1日都在DST周期内或都在DST周期之外。同样,在TZDB中的所有时区中(一个小小的例外),两个偏移量中的较大者为DST偏移量。由于JavaScript getTimezoneOffset返回的是反值,Math.max因此实际上是在返回标准偏移量。该代码是正确的。
马特·约翰逊·品脱

7
但是,如果任何时区曾经更改其定义,使得1月1日和7月1日都在DST中,或者都不在DST中(并且DST仍然适用),则此代码在该时区将不起作用。
马特·约翰逊·品脱

9
总体而言,这是行不通的,例如,某些国家/地区在某些年份未遵守过夏令时,也有一些国家在斋月期间恢复夏令时。紧接着,在某些实现中,日期的ECMAScript定义被破坏,并且TZ环境变量的处理也被破坏。所有这些结合在一起使该方法不可靠。您最好使用不使用日期的库,例如timezonecomplete
rogierschouten 2015年

5
该代码在未遵守DST的国家/地区(例如南非或冰岛)不起作用;也就是说,如果您将其与这些国家/地区的其他时区进行比较,则不会显示该地区的正确时间。建议完全使用UTC,并手动检查现在的时间是否在某个DST范围内。然后,只需将正常时间UTC偏移量更改+1即可获得DST。
Kebman

1
这怎么可能是正确的?例如,德国在2016年10月30日进入夏令时,而美国在2016年11月6日进入夏令时。像这样的不良信息是什么原因造成这样的东西发生:macworld.co.uk/news/apple/...
丹尼尔˚F

22

创建两个日期:一个在六月,一个在一月。比较它们的getTimezoneOffset()值。

  • 如果1月抵消> 6月抵消,则客户在北半球
  • 如果1月抵消额<6月抵消额,则客户在南半球
  • 如果没有差异,则客户端时区不遵守DST

现在检查当前日期的getTimezoneOffset()。

  • 如果等于北半球6月,则当前时区为DST(+1小时)
  • 如果等于一月,南半球,则当前时区为夏令时(+1小时)

为什么需要半球?如果当前日期的getTimezoneOffset()等于两个getTimezoneOffset()中的较小者,那么它的DST还不够吗?[和偏移量是两者之间的差额?]
epeleg 2014年

您不需要半球,因为公认的答案清楚地表明了这一点:)
Jon Nylander 2014年

这行不通。最好的办法是确保您使用UTC时间并手动设置所需偏移量。然后,手动找到同一区域(如果有)的DST的开始和结束。然后,您要检查该区域的时间是否在DST范围内,然后用+1相应地更新偏移量。这样就可以比较遵守DST的国家和不遵守DST的国家。
Kebman

问题是,如何确定客户端计算机Kebman所在时区中的DST目前是否有效,而不是如何显示日期,Web客户端已经为您处理了。
乔恩·尼兰德

您应该在1月和7月(或2月和8月,3月和9月等)之间进行检查,因为它们相距6个月。
kpull1

17

这个答案与接受的答案非常相似,但是不会覆盖Date原型,仅使用一个函数调用来检查夏时制是否有效,而不是两个。


这个想法是,由于没有一个国家会观察到持续7个月的DST [1],因此在一个观察到DST的地区,与1月的UTC时间的偏移量将不同于7月的UTC时间。

虽然夏令时时钟移动向前,JavaScript的总是返回一个更大的标准时间值。因此,获得一月和七月之间的最小偏移量将获得夏令时期间的时区偏移量。

然后,我们检查日期时区是否等于该最小值。如果是这样,那么我们就在DST中;否则我们不是。

以下函数使用此算法。它使用日期对象,如果该日期的夏令时有效,则d返回true该日期,false如果不是,则返回:

function isDST(d) {
    let jan = new Date(d.getFullYear(), 0, 1).getTimezoneOffset();
    let jul = new Date(d.getFullYear(), 6, 1).getTimezoneOffset();
    return Math.max(jan, jul) != d.getTimezoneOffset(); 
}

1
这是可行的,但是如果当前TimeZone中没有DST,则结果也将为true,这是不正确的。如果将其切换为Math.max(...) != d.get...(),则如果在给定的时区中观察到DST并且日期当前在DST中,则它将返回true。如果未观察到DST或日期与标准偏移量匹配,它将返回false。
GreySage

12

今天我也遇到了同样的问题,但是由于夏时制的开始和结束时间与美国不同(至少从我的理解),所以我使用的路线略有不同。

var arr = [];
for (var i = 0; i < 365; i++) {
 var d = new Date();
 d.setDate(i);
 newoffset = d.getTimezoneOffset();
 arr.push(newoffset);
}
DST = Math.min.apply(null, arr);
nonDST = Math.max.apply(null, arr);

然后,您只需将当前时区偏移量与DST和nonDST进行比较,以查看哪一个匹配。


这也是我们的方法。也就是说,找出一年中夏令时在目标时区中发生的变化,并计算当日和最近的更改日期的偏移量。它们将相差一个小时或相等(假设所讨论的时区是小时偏移量)。
希瑟2012年

无需创建365个值,即使没有观察到夏令时,一旦确定偏移量变化后立即停止的二进制搜索方法应更加高效。所有这些方法都假定场所每年都遵守夏时制,这不一定是正确的。地方会不时采用和放弃夏时制(尽管ECMAScript假定当前规则,无论它们涉及的区域如何,始终适用)。
RobG

2
Rob-如果您不知道在哪里搜索(即,您要查找的位置在测试点的上方还是下方),如何通过二进制搜索来做到这一点
epeleg 2014年

9

基于Matt Johanson对Sheldon Griffin提供的解决方案的评论,我创建了以下代码:

    Date.prototype.stdTimezoneOffset = function() {
        var fy=this.getFullYear();
        if (!Date.prototype.stdTimezoneOffset.cache.hasOwnProperty(fy)) {

            var maxOffset = new Date(fy, 0, 1).getTimezoneOffset();
            var monthsTestOrder=[6,7,5,8,4,9,3,10,2,11,1];

            for(var mi=0;mi<12;mi++) {
                var offset=new Date(fy, monthsTestOrder[mi], 1).getTimezoneOffset();
                if (offset!=maxOffset) { 
                    maxOffset=Math.max(maxOffset,offset);
                    break;
                }
            }
            Date.prototype.stdTimezoneOffset.cache[fy]=maxOffset;
        }
        return Date.prototype.stdTimezoneOffset.cache[fy];
    };

    Date.prototype.stdTimezoneOffset.cache={};

    Date.prototype.isDST = function() {
        return this.getTimezoneOffset() < this.stdTimezoneOffset(); 
    };

考虑到所有评论和先前建议的答案,并且特别是它,它试图使世界上最好的东西:

1)缓存每年stdTimezoneOffset的结果,以便在同一年中测试多个日期时无需重新计算。

2)它不假定DST(如果有的话)一定是在7月,并且即使在某个时间,某个地点是任何月份都可以使用。但是,从性能角度来看,如果确实是7月(或近几个月)确实是DST,它将更快地工作。

3)更糟糕的情况是,它将比较每月第一天的getTimezoneOffset。[并且每年进行一次测试]。

它仍然做出的假设是,如果存在夏令时期间,则大于一个月。

如果有人想删除该假设,他可以将循环更改为类似于Aaron Cole提供的solutin中的内容-但我仍然会提前半年跳到发现两个不同的偏移量时退出循环]


4

所述moment.js库提供一个.isDst()在其时间的对象的方法。

moment#isDST检查当前时刻是否为夏令时。

moment([2011, 2, 12]).isDST(); // false, March 12 2011 is not DST
moment([2011, 2, 14]).isDST(); // true, March 14 2011 is DST

我尝试了var moment = require('moment'); this.logger.info(moment([2011,2,12])。isDST()); this.logger.info(moment([2011,2,14])。isDST()); 两者都是错误的
Logan_B

DST更改日期因国家/地区而异,即使同一国家/地区(即亚利桑那州)之间也是如此。在美国是2011年3月13日,在德国是2011年3月31日。所以结果将根据其不同的时区moment.js被配置为工作英寸
丹尼尔˚F

1
它甚至在亚利桑那州之间
Daniel F

3

getTimezoneOffset()在浏览器中,JavaScript中的方法返回从00:00时区偏移的分钟数。例如,夏令时(DST)中的America / New_York时区返回数字300。300分钟是从零开始的5个小时差异。300分钟除以60分钟就是5小时。将每个时区与零时区+00:00 / Etc / GMT /格林威治时间进行比较。

MDN网络文档

您必须知道的下一件事情是,偏移量与实际时区的符号相反。

有关时区的信息由Internet号码分配机构(iana)维护

安娜时区

joda.org提供了格式正确的时区表

乔达时区

+00:00或Etc / GMT为格林威治时间

所有时区都从+00:00 /“ Etc / GMT” /格林威治时间偏移

夏令时总是比夏天的“常规”时间早。您将时钟拨回秋季。(“回滚”口号记住该怎么做)

因此,夏令时(冬季)中的America / New_York时间比常规时间早一小时。因此,例如,夏令时通常在夏季纽约市的下午5点,现在是夏令时的美国/纽约时间下午4点。名称“ America / New_York”时间是“长格式”时区名称。美国的东海岸通常将其时区称为东部标准时间(EST)

如果要将今天的时区偏移量与其他日期的时区偏移量进行比较,则需要知道时区偏移量的数学符号(+/-“正/负”)与时区相反。

查看joda.org上的时区表,并找到“ America / New_York”的时区。“标准偏移”前面将带有负号。

地球绕其轴逆时针旋转。在格林威治观看日出的人比纽约市有人看到日出要早五个小时。在美国东海岸的某人看到日出之后,美国西海岸的某人将看到日出。

有一个原因使您需要了解所有这一切。这样一来,您就可以从逻辑上确定某些JavaScript代码是否正确获取了DST状态,而无需在一年中的不同时间测试每个时区。

想象一下,在纽约市是11月,时钟已经推迟了一个小时。在纽约市的夏季,偏移量是240分钟或4个小时。

您可以通过创建7月的日期然后获取偏移量来进行测试。

var July_Date = new Date(2017, 6, 1);
var july_Timezone_OffSet = July_Date.getTimezoneOffset();

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

什么将打印到浏览器的开发人员工具控制台日志中?

答案是:240

因此,现在您可以在1月创建一个日期,并查看浏览器针对冬季的时区偏移返回的内容。

var Jan_Date = new Date(2017, 0, 1);//Month is zero indexed - Jan is zero
var jan_Timezone_OffSet = Jan_Date.getTimezoneOffset();

console.log('jan_Timezone_OffSet: ' + jan_Timezone_OffSet)

答案是:300

显然300比240大。那么,这意味着什么呢?您是否应该编写测试冬季偏移量大于夏季偏移量的代码?还是夏季偏移量小于冬季偏移量?如果夏令时区偏移量和冬时区偏移量之间存在差异,则可以假定该时区使用了DST。但这并不能告诉您今天是否在浏览器时区使用DST。因此,您需要获取今天的时区偏移量。

var today = new Date();
var todaysTimeZone = today.getTimezoneOffset();

console.log('todaysTimeZone : ' + todaysTimeZone)

答案是:-取决于一年中的时间

如果今天的时区偏移量和夏令时区偏移量是相同的,夏季和冬季的时区偏移量是不同的,然后通过逻辑推演,今天必须不能在DST。

您是否可以忽略比较夏季和冬季时区偏移量(以了解是否将DST用于该时区),而仅将今天的时区偏移量与夏季TZ偏移量进行比较,并始终获得正确的答案?

today's TZ Offset !== Summer TZ Offset

好吧,今天是冬季还是夏季?如果您知道,则可以采用以下逻辑:

if ( it_is_winter && ( todays_TZ_Offset !== summer_TZ_Offset) {
  var are_We_In_DST = true;
}

但是问题是,您不知道今天的日期是冬天还是夏天。每个时区都有自己的DST开始和停止时间的规则。您需要跟踪世界上每个时区的每个时区规则。因此,如果有更好更好的方法,那么最好也这样做。

我们剩下的是,您需要知道该时区是否使用DST,然后将今天的时区偏移量与夏令时区偏移量进行比较。这将始终为您提供可靠的答案。

最终的逻辑是:

if ( DST_Is_Used_In_This_Time_Zone && ( todays_TZ_Offset !== summer_TZ_Offset) {
  var are_We_In_DST = true;
}

确定浏览器中的时区是否使用DST的函数:

function is_DST_Used_In_This_TimeZone() {
  var Jan_Date, jan_Timezone_OffSet, July_Date, july_Timezone_OffSet 
      offsetsNotEqual, thisYear, today;

  today = new Date();//Create a date object that is now
  thisYear = today.getFullYear();//Get the year as a number

  Jan_Date = new Date(thisYear, 0, 1);//Month is zero indexed - Jan is zero
  jan_Timezone_OffSet = Jan_Date.getTimezoneOffset();

  console.log('jan_Timezone_OffSet: ' + jan_Timezone_OffSet)

  July_Date = new Date(thisYear, 6, 1);
  july_Timezone_OffSet = July_Date.getTimezoneOffset();

  console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

  offsetsNotEqual = july_Timezone_OffSet !== jan_Timezone_OffSet;//True if not equal

  console.log('offsetsNotEqual: ' + offsetsNotEqual);

  return offsetsNotEqual;//If the offsets are not equal for summer and
       //winter then the only possible reason is that DST is used for
       //this time zone
}

根据dateandtime.com, DST从2019年3月10日开始,因此是夏天而不是冬天,纽约的DST偏移量是-4,而不是-5。
jk7'4-4-10

如果需要对答案进行改进或修正,请进行修改,然后我们会对其进行审核。
艾伦·威尔斯

2

使用Moment.js(https://momentjs.com/

moment().isDST(); 如果观察到日光节约,将会给您。

它还具有帮助功能,可以为您计算相对时间。您不需要手动计算,例如moment("20200105", "YYYYMMDD").fromNow();


1

您近在咫尺,但是还差一点。您不需要计算自己的时间,因为它是您自己的时钟的结果。它可以检测您是否在您所在的位置使用夏令时,而不是在偏移产生的远程位置:

newDateWithOffset = new Date(utc + (3600000*(offset)));

如果他们在DST中,这仍然是错误的,并且需要一个小时的时间。如果它们当前是否在DST中,则需要一个远程时间帐户,并进行相应的调整。尝试计算该时间并将时钟更改为-假设是2015年2月1日,然后将时钟重置为一个小时,就好像在DST之外。然后计算仍要落后2小时的位置的偏移量。它将在两个小时窗口之前显示一个小时。您仍然需要考虑小时数并进行调整。我是在纽约和丹佛做的,总是在丹佛走错(提前一个小时)。


1

我发现将Moment.js库与此处描述的某些概念(1月至6月相比)结合使用非常有效。

这个简单的函数将返回用户所在的时区是否遵守夏令时:

function HasDST() {
    return moment([2017, 1, 1]).isDST() != moment([2017, 6, 1]).isDST();
}

一种简单的检查方法(在Windows上)可以将您的时区更改为非DST时区,例如Arizona将返回false,而EST或PST将返回true。

在此处输入图片说明


1

适用于所有时区的面向未来的解决方案

  1. x是毫秒到感兴趣的一年的期望数量,而不在夏令保。
  2. y是因为毫秒数时代从感兴趣的日期的年份的开始。
  3. z是毫秒数,因为时代完整的日期和感兴趣的时间的
  4. 我们t是两者的减法xy来自zz - y - x。由于DST,这将产生偏移。
  5. 如果t为零,则DST无效。如果t不为零,则DST生效。

(function(){"use strict";
function dstOffsetAtDate(dateInput) {
    var fullYear = dateInput.getFullYear()|0;
	// "Leap Years are any year that can be exactly divided by 4 (2012, 2016, etc)
 	//   except if it can be exactly divided by 100, then it isn't (2100,2200,etc)
 	//	  except if it can be exactly divided by 400, then it is (2000, 2400)"
	// (https://www.mathsisfun.com/leap-years.html).
    var isLeapYear = ((fullYear & 3) | (fullYear/100 & 3)) === 0 ? 1 : 0;
	// (fullYear & 3) = (fullYear % 4), but faster
    //Alternative:var isLeapYear=(new Date(currentYear,1,29,12)).getDate()===29?1:0
    var fullMonth = dateInput.getMonth()|0;
    return (
        // 1. We know what the time since the Epoch really is
        (+dateInput) // same as the dateInput.getTime() method
        // 2. We know what the time since the Epoch at the start of the year is
        - (+new Date(fullYear, 0, 0)) // day defaults to 1 if not explicitly zeroed
        // 3. Now, subtract what we would expect the time to be if daylight savings
        //      did not exist. This yields the time-offset due to daylight savings.
        - ((
            ((
                // Calculate the day of the year in the Gregorian calendar
                // The code below works based upon the facts of signed right shifts
                //    • (x) >> n: shifts n and fills in the n highest bits with 0s 
                //    • (-x) >> n: shifts n and fills in the n highest bits with 1s
                // (This assumes that x is a positive integer)
                (31 & ((-fullMonth) >> 4)) + // January // (-11)>>4 = -1
                ((28 + isLeapYear) & ((1-fullMonth) >> 4)) + // February
                (31 & ((2-fullMonth) >> 4)) + // March
                (30 & ((3-fullMonth) >> 4)) + // April
                (31 & ((4-fullMonth) >> 4)) + // May
                (30 & ((5-fullMonth) >> 4)) + // June
                (31 & ((6-fullMonth) >> 4)) + // July
                (31 & ((7-fullMonth) >> 4)) + // August
                (30 & ((8-fullMonth) >> 4)) + // September
                (31 & ((9-fullMonth) >> 4)) + // October
                (30 & ((10-fullMonth) >> 4)) + // November
                // There are no months past December: the year rolls into the next.
                // Thus, fullMonth is 0-based, so it will never be 12 in Javascript
                
                (dateInput.getDate()|0) // get day of the month
				
            )&0xffff) * 24 * 60 // 24 hours in a day, 60 minutes in an hour
            + (dateInput.getHours()&0xff) * 60 // 60 minutes in an hour
            + (dateInput.getMinutes()&0xff)
        )|0) * 60 * 1000 // 60 seconds in a minute * 1000 milliseconds in a second
        - (dateInput.getSeconds()&0xff) * 1000 // 1000 milliseconds in a second
        - dateInput.getMilliseconds()
    );
}

// Demonstration:
var date = new Date(2100, 0, 1)
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\t"+dstOffsetAtDate(date)/60/60/1000+"h\t"+date);
date = new Date(1900, 0, 1);
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\t"+dstOffsetAtDate(date)/60/60/1000+"h\t"+date);

// Performance Benchmark:
console.time("Speed of processing 16384 dates");
for (var i=0,month=date.getMonth()|0; i<16384; i=i+1|0)
    date.setMonth(month=month+1+(dstOffsetAtDate(date)|0)|0);
console.timeEnd("Speed of processing 16384 dates");
})();

我认为,出于多种原因,上述代码段优于此处发布的所有其他答案。

  • 这个答案适用于所有时区,甚至包括南极洲/卡西
  • 夏令时非常容易发生变化。可能是从现在开始的20年后,某个国家/地区可能会有3个DST周期,而不是正常的2个。此代码通过返回以毫秒为单位的DST偏移量来处理这种情况,而不仅是DST是否有效。
  • 一年中各个月份的大小以及Le年的工作方式非常适合使我们的时间与太阳同步。哎呀,它是如此完美地工作,以至于我们只需要在这里和那里调整几秒钟就可以了。我们当前的of年系统自15822月24日起生效,并且在可预见的将来可能会继续有效。
  • 此代码在不使用DST的时区中工作。
  • 该代码在实施DST之前的历史时期(例如1900年代)起作用。
  • 此代码已最大程度地优化了整数,如果在紧密循环中调用,则不会给您带来任何问题。运行上面的代码段后,向下滚动到输出的底部以查看性能基准。我的计算机在Chrome上能够在约97毫秒内处理16384个日期。

但是,如果您没有准备超过2个DST周期,则可以使用以下代码来确定DST是否有效为布尔值。

function isDaylightSavingsInEffect(dateInput) {
    // To satisfy the original question
    return dstOffsetAtDate(dateInput) !== 0;
}

0

我最近需要使用UTC和DST创建日期字符串,并根据Sheldon的回答将其组合在一起:

Date.prototype.getTimezone = function(showDST) {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);

    var utcOffset = new Date().getTimezoneOffset() / 60 * -1;
    var dstOffset = (jan.getTimezoneOffset() - jul.getTimezoneOffset()) / 60;

    var utc = "UTC" + utcOffset.getSign() + (utcOffset * 100).preFixed(1000);
    var dst = "DST" + dstOffset.getSign() + (dstOffset * 100).preFixed(1000);

    if (showDST) {
        return utc + " (" + dst + ")";
    }

    return utc;
}
Number.prototype.preFixed = function (preCeiling) {
    var num = parseInt(this, 10);
    if (preCeiling && num < preCeiling) {
        num = Math.abs(num);
        var numLength		 = num.toString().length;
        var preCeilingLength = preCeiling.toString().length;
        var preOffset		 = preCeilingLength - numLength;
        for (var i = 0; i < preOffset; i++) {
            num = "0" + num;
        }
    }
    return num;
}
Number.prototype.getSign = function () {
    var num	 = parseInt(this, 10);
    var sign = "+";
    if (num < 0) {
        sign = "-";
    }
    return sign;
}

document.body.innerHTML += new Date().getTimezone() + "<br>";
document.body.innerHTML += new Date().getTimezone(true);
<p>Output for Turkey (UTC+0200) and currently in DST: &nbsp; UTC+0300 (DST+0100)</p>
<hr>


0

使用时是否有问题 Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

1月01日,星期六100050 00:00:00 GMT-0500(东部标准时间)

"" + new Date(...)

星期日五月01 100033 00:00:00 GMT-0400(东部夏令时间)

这似乎与所有浏览器兼容。


是的,它不适用于世界各地。在欧洲的夏季,您会遇到"Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"
Tadej Krevh

0

ES6风格

Math.min(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset() * -1));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.