夏令时“bug”

问题描述 投票:0回答:4

以下是连续两天之间的小时数计算:

(AbsoluteTime[{2011, 3, 14}] - AbsoluteTime[{2011, 3, 13}]) / 3600

所以您可能不会对 Mathematica 的回归感到惊讶

24
。 但这是令人惊讶的。所有其他编程语言都会说 23,因为 3 月 13 日是夏令时的开始。 我需要我的 Mathematica 程序在这方面与其他语言保持一致。 你会推荐什么?

要明确问题:

AbsoluteTime[{2011,3,13}]
给出
3508963200
。减去 unix 纪元,即为
1299988800
的 unix 时间。但是将 unixtime 提供给任何其他编程语言并询问它对应的日期,它会说 3 月 12 日而不是 3 月 13 日。 (同样的事情在 3 月 14 日也可以正常工作。)

(好吧,我知道你很想知道为什么我想要遵守所有那些明显不完整的语言。 嗯,首先,其他语言都有一个观点:由于“向前推进”,3 月 14 日午夜比 3 月 13 日午夜晚了 23 个小时。 为什么我真正关心:我们使用 unixtime 作为日期的规范表示。因此,当我想将“2011-03-13 00:00 EST”传达给另一个程序时,我发送 AbsoluteTime 减去 unix 纪元。 这在 Mathematica 中工作得很好。当我将 unixtime 转换回来时,我再次得到“2011-03-13 00:00 EST”。 但是,如果我将该 unixtime 发送到另一个程序,它会将其解释为“2011-03-12 23:00 EST”,这结果是一个问题,因为那是前一天。)

datetime wolfram-mathematica
4个回答
4
投票

您可以使用 Java 与 Unix 时间来回转换:

Needs["JLink`"]
LoadJavaClass["java.util.Calendar"]

ToUnixTime[year_, month_, day_, hour_:0, minute_:0, second_:0] :=
  JavaBlock[
    Module[{calendar}
    , calendar = java`util`Calendar`getInstance[]
    ; calendar@set[year, month - 1, day, hour, minute, second]
    ; Floor[calendar@getTimeInMillis[] / 1000]
    ]
  ]

FromUnixTime[time_Integer] :=
  JavaBlock[
    Module[{calendar}
    , calendar = java`util`Calendar`getInstance[]
    ; calendar@setTimeInMillis[time * 1000]
    ; calendar@getTime[]@toString[]
    ]
  ]

使用示例:

In[19]:= ToUnixTime[2011, 4, 26, 1, 2, 3]
Out[19]= 1303801323

In[20]:= FromUnixTime[1303801323]
Out[20]= "Tue Apr 26 01:02:03 MDT 2011"

如前所述,前面的定义将在转换中使用您的本地时区和区域设置。


3
投票

我于 2010 年 8 月 4 日在 comp.soft-sys.math.mathematica 中发布了相关问题:

http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/6f50f6930f1ac325/

事实证明,M7 的 Mac 版本中存在(曾经是?)一个错误,该错误在调用 AbsoluteTime 时基本上忽略了时区规范。 我认为这个问题在 M8 中已得到解决,但我不确定。


3
投票

你可以尝试这样的事情:

tzDreeves = {"Buenos Aires", "13 March", "13 September", 3, 4};

tZone[date_, tz_] := 
 Piecewise[{{tz[[4]],
   First@
    DateDifference[tz[[2]]<>" "<>DateString[date,"Year"], date, "Second"] > 0 &&
   First@
    DateDifference[tz[[3]]<>" "<>DateString[date,"Year"], date, "Second"] < 0}},
 tz[[5]]];

myTimeDif[d1_, d2_, tz_] := 
 DateDifference[DateList@AbsoluteTime[d1, TimeZone -> tZone[d1, tz]], 
                DateList@AbsoluteTime[d2, TimeZone -> tZone[d2, tz]], "Second"]


myTimeDif["March 13, 2011", "March 14, 2011", tzDreeves]
myTimeDif["March 12, 2011", "March 13, 2011", tzDreeves]  

->

{82800,Second}  -> 23 hours
{86400,Second}  -> 24 hours   

在下面的例子中你可以看到DS的效果。我们绘制 DST 边界上固定日期的时差:

data = Table[{
         DateList@DatePlus["March 12, 2011, 11PM", {i 10, "Minute"}], 
         First@myTimeDif[DatePlus["March 12, 2011, 11PM", {i 10, "Minute"}], 
                         "March 14, 2011, 2 AM", tzDreeves]},
       {i, 1, 13}];

DateListPlot[data, 
 DateTicksFormat -> {"MonthNameShort", " ", "Day", "\n ", "Time"}, 
 GridLines -> {{{{2011, 3, 13}, Red}}, None}, 
 PlotStyle -> PointSize[Large]]

enter image description here


0
投票

现代爪哇

对于行业领先的日期时间框架,请查看 Java 8+ 中的 java.time 类。

定义您的两个日期。

LocalDate
类表示仅日期值,没有时间、没有时区或与 UTC 的偏移量。

LocalDate date = LocalDate.of ( 2011 , 3 , 13 ) ;
LocalDate nextDate = date.plusDays( 1 ) ;  // The 14th.

我们需要确定每个日期一天的开始时刻。为此,我们需要一个时区。

ZoneId z = ZoneId.of( "America/Edmonton" ) ;

应用该时区来确定一天的第一时刻。不要假设这一天是从 00:00 开始的。在某些时区的某些日期,这一天可能会在其他时间开始,例如 01:00。让 java.time 确定。 该时刻由

ZonedDateTime

 类表示。
ZonedDateTime start = date.atStartOfDay ( z ) ; ZonedDateTime end = nextDate.atStartOfDay ( z ) ;

计算这两个时刻之间经过的时间。要以小时-分钟-秒为单位表示与时间线无关的时间跨度,请使用 

Duration

 类。
Duration d = Duration.between ( start , end ) ;

查看此代码
在 Ideone.com 上运行

2011-03-13T00:00-07:00[America/Edmonton] 2011-03-14T00:00-06:00[America/Edmonton] PT23H

	
© www.soinside.com 2019 - 2024. All rights reserved.