Javascript日期不一致

时间:2014-03-14 17:35:32

标签: javascript date

所以我知道之前已经讨论过这个问题,但我真的想要一些有用的输入。我正在写一个日历,需要添加日期,我遇到了一个早期的帖子(Add days to JavaScript Date),但它提出了更多的排队而不是答案。所以我去了自己的代码,我很亲密。这就是我所拥有的:

Date.prototype.add = function(period, value, ignoreDaylightSaving)
{
    var Day = this.getDate();
    var Month = this.getMonth();
    var Year = this.getFullYear();
    var Hours = this.getHours();
    var Mins = this.getMinutes();
    var Secs = this.getSeconds();
    var MilliSecs = this.getMilliseconds();
    var TestDate;
    var IgnoreDS = false;
    var TZOffset1 = 0;
    var TZOffset2 = 0;

    if (typeof(ignoreDaylightSaving) == "boolen")
    {
        IgnoreDS = ignoreDaylightSaving;
    }

    switch (period.toUpperCase())
    {
    case "D":
        Day += value;
        break;

    case "M":
        Month += value;
        break;

    case "Y":
        Year += value;
        break;

    case "H":
        Hours += value;
        break;

    case "N":
        Mins += value;
        break;

    case "S":
        Secs += value;
        break;

    case "MS":
        MilliSecs += value;
    }

    // Standardise Daylight Saving cut off.
    if (IgnoreDS == false)
    {
        TestDate = new Date(Year, Month, Day, Hours, Mins, Secs, MilliSecs);
        TZOffset1 = this.getTimezoneOffset();
        TZOffset2 = TestDate.getTimezoneOffset();

        if (value > 0)
        {
            if (this > TestDate)
            {
                if (TZOffset1 == TZOffset2)
                {
                    Hours += 1;
                }
            }
        } else {
            if (this < TestDate)
            {
                if (TZOffset1 == TZOffset2)
                {
                    Hours -= 1;
                }
            }
        }
    }

    return(new Date(Year, Month, Day, Hours, Mins, Secs, MilliSecs));
}

它依赖于Javascript来为我做计算。在内部,日期和时间只是数字,所以如果你传递一组值,无论它们是否在范围内,javascript只是将它们全部乘以得到内部数字。只有当您将日期函数应用于该数字时,它才会转换为我们识别的日期。

所以我的逻辑:

* split down the Date into its components
* add the value you want to one of the components
* create a new date from the components.

我已经用IE和Chrome的闰年进行了测试。

夏令时是另一回事。在英国,英国夏令时开始于2014年3月30日凌晨1点30分。如果我设定日期为2014年3月30日00:59:00并添加2分钟,Chrome会给我'2014年3月30日00:01:00'(格林威治标准时间标准时间) ,但IE给了我'2014年3月30日02:01:00'(GMT夏令时)。

两个浏览器都有效地说“你不能在2014年3月30日上午01:01因为它不存在”。 IE进入下一次(实际上是调整时钟),而Chrome只会让你退回一小时,让你保持GMT标准时间。当夏令时结束时,他们以相反的方式做到这一点 - IE让你在夏令时,Chrome会为你调整时钟。我编写了这个代码,用于从GMT Standard到GMT Summertime(请参阅标准化夏令时中的区块)。

很难对GMT Summertime转为GMT标准的不一致进行编码。我甚至写了一些javascript,通过每个月,然后是一天一小时来查找日期的变化。但IE给Chrome提供了不同的时间。代码:

Date.prototype.getDaylightSavingDate = function(year)
{
    var DSStart = new Date();
    var DSEnd = new Date();

    var MonthLoop;
    var d1 = new Date();
    var d2 = new Date();
    var ThreshholdTZOffsets = new Array();
    var ThreshholdMonths = new Array();
    var ThreshholdDays = new Array();
    var ThreshholdHours = new Array();
    var ThisTZOffset;
    var PrevTZOffset;
    var THCount;


    THCount = 0;
    for (DateLoop=0; DateLoop < 12; DateLoop++)
    {
        d1 = new Date(year, DateLoop, 1);
        ThisTZOffset = d1.getTimezoneOffset();

        d2 = new Date(year, DateLoop-1, 1)
        PrevTZOffset = d2.getTimezoneOffset();

        if (PrevTZOffset != ThisTZOffset)
        {
            ThreshholdMonths[THCount] = DateLoop-1;
            ThreshholdTZOffsets[THCount] = ThisTZOffset;
            THCount += 1;
        }

        PrevTZOffset = ThisTZOffset
    }

    for (DateLoop=0; DateLoop<ThreshholdMonths.length; DateLoop++)
    {
        for (DayLoop=1; DayLoop < 32; DayLoop++)
        {
            d1 = new Date(year, ThreshholdMonths[DateLoop], DayLoop);
            ThisTZOffset = d1.getTimezoneOffset();

            d2 = new Date(year,  ThreshholdMonths[DateLoop], DayLoop-1);
            PrevTZOffset = d2.getTimezoneOffset();

            if (PrevTZOffset != ThisTZOffset)
            {
                ThreshholdDays[DateLoop] = DayLoop-1;
            }

            PrevTZOffset = ThisTZOffset
        }
    }

    for (DateLoop=0; DateLoop<ThreshholdMonths.length; DateLoop++)
    {
        for (HourLoop=0; HourLoop < 23; HourLoop++)
        {
            d1 = new Date(year, ThreshholdMonths[DateLoop], ThreshholdDays[DateLoop], HourLoop, 0, 0);
            ThisTZOffset = d1.getTimezoneOffset();

            d2 = new Date(year, ThreshholdMonths[DateLoop], ThreshholdDays[DateLoop], HourLoop-1, 0, 0);
            PrevTZOffset = d2.getTimezoneOffset();

            if (PrevTZOffset != ThisTZOffset)
            {
                ThreshholdHours[DateLoop] = HourLoop;
            }

            PrevTZOffset = ThisTZOffset
        }
    }

    if (ThreshholdHours.length == 2)
    {
        DSStart = new Date(year, ThreshholdMonths[0], ThreshholdDays[0], ThreshholdHours[0],0,0,0);
        DSEnd = new Date(year, ThreshholdMonths[1], ThreshholdDays[1], ThreshholdHours[1],0,0,0);

        return({start:DSStart,end:DSEnd})
    }
}

如果在 IE 中调用此例程并调试它ThreshholdDays [0] = 1,并且ThreshholdDays [1] = 2。在 Chrome 中,反之亦然:ThreshholdDays [0] = 2,ThreshholdDays [1] = 1。

我的HTML用于调用例程:

<!DOCTYPE HTML>
<html dir="ltr" lang="en-gb" xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>Test Dates</title>

<script language="javascript" type="text/javascript" src="LIBS/general.js"></script>
</head>

<body>
<div>
<script language="javascript" type="text/javascript">
var d1 = new Date(2014, 9, 26, 2,1,0);
var d2 = d1.add("n", -2, true);
var ds1 = d1.getDaylightSavingDate(2014);

alert(ds1.start + ", " + ds1.end);
alert(d1 + ", " + d2 + ", " + (d2-d1));

</script>
</div>
</body>
</html>

有人在没有明确编写每个浏览器的情况下想到另一种方法吗?

1 个答案:

答案 0 :(得分:0)

如果将6月份日期的本地时区偏移量与1月份的日期进行比较,则可以判断DST是否适用。

在赤道以南,使用夏令时,1月总是在夏令时,赤道以北,6月总是在夏令时。

您可以依次将Date对象推进到月,日,小时和分钟,查看时区偏移的差异,从而找到DST和标准时间开始的月,日,小时和分钟。 这是一个繁忙的功能,但只需要在日历应用程序中执行一年。

函数getDST返回一个数组,其中Date对象代表给定年份的标准时间的第一分钟, 该年度夏令时的第一分钟,以及以分钟为单位的抵消差异。

(第二个函数返回日期和日历中该日期显示的消息)

测试此类功能的最佳方法是使用dst启用计算机中的时区,以获得尽可能多的时区。

function getDST(y){
    y= y || new Date().getFullYear();
    var D1= new Date(y, 0, 1), D2= new Date(y, 5, 1), 
    off1= D1.getTimezoneOffset(), off2= D2.getTimezoneOffset(), 
    diff= off2-off1;
    if(diff=== 0) return ;
    var stdTime= D1, dstTime= D2, 
    std1= 11, dst1= 5, 
    stdOffset= off1, dstOffset= off2, 
    isDst, isStd, one= 1;
    if(diff>0){
        diff*= -1;
        stdOffset= off2;
        dstOffset= off1;
        std1= 5;
        dst1= 11;
    }
    function isDst(D){
        return D.getTimezoneOffset()=== dstOffset;
    }
    function isStd(D){
        return D.getTimezoneOffset()=== stdOffset;
    }
    function edgeTz(D, m, check){
        D.setMonth(m);
        while(check(D)) D.setMonth(m--);
        D.setMonth(D.getMonth()+1);
        while(check(D)) D.setDate(D.getDate()-1);
        one= 1;
        while(!check(D)) D.setHours(one++);
        D.setHours(D.getHours()-1);
        one= 1;
        while(!check(D)) D.setMinutes(one++);
        return D;
    }
    stdTime= edgeTz(stdTime, std1, isStd);
    dstTime= edgeTz(dstTime, dst1, isDst);
    return [stdTime, dstTime, diff];
}

//标准和dst的本地开始时间: 的 getDST(2014)。加入( '\ n');

//result for EST

Sun Nov 02 2014 02: 00: 00 GMT-0500(Eastern Daylight Time)
Sun Mar 09 2014 03: 00: 00 GMT-0400(Eastern Standard Time)
-60

//日历备注:

function tzReport(y){
    var z= getDST(y);
    var dstMsg, stdMsg, changeStd, changeDst, 
    stdTime= z[0], dstTime= z[1], diff= z[2];
    changeStd= new Date(stdTime);
    changeStd.setDate(changeStd.getDate()+1);
    changeStd.setMinutes(changeStd.getMinutes()-diff);
    stdMsg= 'Standard Time begins. At '+
    changeStd.timeString()+', clocks return to '+stdTime.timeString()+'.';
    changeDst= new Date(dstTime);
    changeDst.setDate(changeDst.getDate()+1);
    changeDst.setMinutes(changeDst.getMinutes()+diff);
    dstMsg= 'DST begins. At '+changeDst.timeString()+
    ', clocks advance to '+dstTime.timeString()+'.';
    return [[stdTime.toLocaleDateString(), stdMsg], 
    [dstTime.toLocaleDateString(), dstMsg]];
}

//日历通知: tzReport(2014).join('\ n');

Sunday, November 02, 2014, 
Standard Time begins.
At 3: 00 am, clocks return to 2: 00 am.
Sunday, March 09, 2014, DST begins.
At 2: 00 am, clocks advance to 3: 00 am.