- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我遇到了 Joda 问题,我认为这可能是一个错误。然而,我很可能在使用库时犯了错误,所以请给我你的反馈。
我们一直在生产中使用 joda 在我们的数据库存储格式 (UTC) 和用户的时区偏好之间转换时间。使用该系统的员工都在不遵守夏令时的亚利桑那州工作。除其他外,该系统跟踪全国体育赛事的开始时间。
Joda 对我们来说工作得很好,直到我们注意到在时间更改的前一天我们得到了一些不正确的结果。我们发现 joda 似乎在 UTC 午夜改为夏令时,而不是在特定时区的适当时间。此外,仅当将 DST 观察状态之间的时间转换为非 DST 状态(如亚利桑那州)时,才会出现此问题。
我制作了一个完整的测试用例来说明这个问题。正如您将看到的,joda 为所有 US/Eastern -> US/Pacific 测试用例提供了预期的结果。对于 US/Arizona -> US/Pacific,它在 11 月变化之前和之后的全年都有效。然而,在时间更改当天(11 月 6 日),时间不正确。行军时间的变化也可能存在问题,但我还没有对其进行详尽的测试。
这是所提供测试的输出(11 月 6 日的条目说明了错误):
=== November 1st, Expected Result (0 hour) ===
java:
Converting 2010-11-01 09:00 from US/Arizona to US/Pacific.
Result: 2010-11-01 09:00. Change (0 hour).
joda:
Converting 2010-11-01 09:00 from US/Arizona to US/Pacific.
Result: 2010-11-01 09:00. Change (0 hour).
=======================================
=== November 6th, Expected Result (0 hour) ===
java:
Converting 2010-11-06 09:00 from US/Arizona to US/Pacific.
Result: 2010-11-06 09:00. Change (0 hour).
joda:
Converting 2010-11-06 09:00 from US/Arizona to US/Pacific.
Result: 2010-11-06 08:00. Change (-1 hour).
=======================================
=== November 12th, Expected Result (-1 hour) ===
java:
Converting 2010-11-12 09:00 from US/Arizona to US/Pacific.
Result: 2010-11-12 08:00. Change (-1 hour).
joda:
Converting 2010-11-12 09:00 from US/Arizona to US/Pacific.
Result: 2010-11-12 08:00. Change (-1 hour).
=======================================
=== March 12th, Expected Result (-1 hour) ===
java:
Converting 2010-03-12 09:00 from US/Arizona to US/Pacific.
Result: 2010-03-12 08:00. Change (-1 hour).
joda:
Converting 2010-03-12 09:00 from US/Arizona to US/Pacific.
Result: 2010-03-12 08:00. Change (-1 hour).
=======================================
=== March 14th, Expected Result (0 hour) ===
java:
Converting 2010-03-14 09:00 from US/Arizona to US/Pacific.
Result: 2010-03-14 09:00. Change (0 hour).
joda:
Converting 2010-03-14 09:00 from US/Arizona to US/Pacific.
Result: 2010-03-14 09:00. Change (0 hour).
=======================================
=== November 1st, Expected Result (-3 hour) ===
java:
Converting 2010-11-01 09:00 from US/Eastern to US/Pacific.
Result: 2010-11-01 06:00. Change (-3 hour).
joda:
Converting 2010-11-01 09:00 from US/Eastern to US/Pacific.
Result: 2010-11-01 06:00. Change (-3 hour).
=======================================
=== November 6th, Expected Result (-3 hour) ===
java:
Converting 2010-11-06 09:00 from US/Eastern to US/Pacific.
Result: 2010-11-06 06:00. Change (-3 hour).
joda:
Converting 2010-11-06 09:00 from US/Eastern to US/Pacific.
Result: 2010-11-06 06:00. Change (-3 hour).
=======================================
=== November 12th, Expected Result (-3 hour) ===
java:
Converting 2010-11-12 09:00 from US/Eastern to US/Pacific.
Result: 2010-11-12 06:00. Change (-3 hour).
joda:
Converting 2010-11-12 09:00 from US/Eastern to US/Pacific.
Result: 2010-11-12 06:00. Change (-3 hour).
=======================================
=== March 12th, Expected Result (-3 hour) ===
java:
Converting 2010-03-12 09:00 from US/Eastern to US/Pacific.
Result: 2010-03-12 06:00. Change (-3 hour).
joda:
Converting 2010-03-12 09:00 from US/Eastern to US/Pacific.
Result: 2010-03-12 06:00. Change (-3 hour).
=======================================
=== March 14th, Expected Result (-3 hour) ===
java:
Converting 2010-03-14 09:00 from US/Eastern to US/Pacific.
Result: 2010-03-14 06:00. Change (-3 hour).
joda:
Converting 2010-03-14 09:00 from US/Eastern to US/Pacific.
Result: 2010-03-14 06:00. Change (-3 hour).
=======================================
这是完整的测试用例:
package com.test.time;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import org.joda.time.DateTimeZone;
import org.junit.Before;
import org.junit.Test;
public class TimeTest {
Calendar nov6;
Calendar nov1;
Calendar nov12;
Calendar mar12;
Calendar mar14;
@Before
public void doBefore() {
// November 1st 2010, 9:00pm (DST is active)
nov1 = Calendar.getInstance();
nov1.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
nov1.set(Calendar.HOUR_OF_DAY, 21);
nov1.set(Calendar.MINUTE, 0);
nov1.set(Calendar.SECOND, 0);
nov1.set(Calendar.YEAR, 2010);
nov1.set(Calendar.MONTH, 10); // November
nov1.set(Calendar.DATE, 1);
// November 6st 2010, 9:00pm (DST is still active until early AM
// november 7th)
nov6 = Calendar.getInstance();
nov6.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
nov6.set(Calendar.HOUR_OF_DAY, 21);
nov6.set(Calendar.MINUTE, 0);
nov6.set(Calendar.SECOND, 0);
nov6.set(Calendar.YEAR, 2010);
nov6.set(Calendar.MONTH, 10); // November
nov6.set(Calendar.DATE, 6);
// November 12th 2010, 9:00pm (DST has ended)
nov12 = Calendar.getInstance();
nov12.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
nov12.set(Calendar.HOUR_OF_DAY, 21);
nov12.set(Calendar.MINUTE, 0);
nov12.set(Calendar.SECOND, 0);
nov12.set(Calendar.YEAR, 2010);
nov12.set(Calendar.MONTH, 10); // November
nov12.set(Calendar.DATE, 12);
// March 12th 2011, 9:00pm (DST has ended, will begin early a.m. march
// 13th)
mar12 = Calendar.getInstance();
mar12.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
mar12.set(Calendar.HOUR_OF_DAY, 21);
mar12.set(Calendar.MINUTE, 0);
mar12.set(Calendar.SECOND, 0);
mar12.set(Calendar.YEAR, 2010);
mar12.set(Calendar.MONTH, 2); // March
mar12.set(Calendar.DATE, 12);
// March 14th 2011, 9:00pm (DST has started)
mar14 = Calendar.getInstance();
mar14.setTimeZone(TimeZone.getTimeZone("US/Arizona"));
mar14.set(Calendar.HOUR_OF_DAY, 21);
mar14.set(Calendar.MINUTE, 0);
mar14.set(Calendar.SECOND, 0);
mar14.set(Calendar.YEAR, 2010);
mar14.set(Calendar.MONTH, 2); // March
mar14.set(Calendar.DATE, 14);
}
@Test
public void testArizonaToPacific() {
System.out.println("=== November 1st, Expected Result (0 hour) ===");
timeTestJava(nov1.getTime(), "US/Arizona", "US/Pacific");
timeTestJoda(nov1.getTime(), "US/Arizona", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== November 6th, Expected Result (0 hour) ===");
timeTestJava(nov6.getTime(), "US/Arizona", "US/Pacific");
timeTestJoda(nov6.getTime(), "US/Arizona", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== November 12th, Expected Result (-1 hour) ===");
timeTestJava(nov12.getTime(), "US/Arizona", "US/Pacific");
timeTestJoda(nov12.getTime(), "US/Arizona", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== March 12th, Expected Result (-1 hour) ===");
timeTestJava(mar12.getTime(), "US/Arizona", "US/Pacific");
timeTestJoda(mar12.getTime(), "US/Arizona", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== March 14th, Expected Result (0 hour) ===");
timeTestJava(mar14.getTime(), "US/Arizona", "US/Pacific");
timeTestJoda(mar14.getTime(), "US/Arizona", "US/Pacific");
System.out.println("=======================================\n");
}
@Test
public void testEasternToPacific() {
System.out.println("=== November 1st, Expected Result (-3 hour) ===");
timeTestJava(nov1.getTime(), "US/Eastern", "US/Pacific");
timeTestJoda(nov1.getTime(), "US/Eastern", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== November 6th, Expected Result (-3 hour) ===");
timeTestJava(nov6.getTime(), "US/Eastern", "US/Pacific");
timeTestJoda(nov6.getTime(), "US/Eastern", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== November 12th, Expected Result (-3 hour) ===");
timeTestJava(nov12.getTime(), "US/Eastern", "US/Pacific");
timeTestJoda(nov12.getTime(), "US/Eastern", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== March 12th, Expected Result (-3 hour) ===");
timeTestJava(mar12.getTime(), "US/Eastern", "US/Pacific");
timeTestJoda(mar12.getTime(), "US/Eastern", "US/Pacific");
System.out.println("=======================================\n");
System.out.println("=== March 14th, Expected Result (-3 hour) ===");
timeTestJava(mar14.getTime(), "US/Eastern", "US/Pacific");
timeTestJoda(mar14.getTime(), "US/Eastern", "US/Pacific");
System.out.println("=======================================\n");
}
// print some output from the test
private void print(Date startTime, String text, String from, String to,
Date output) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm");
System.out.println(text + ":");
System.out.println("Converting " + sdf.format(startTime) + " from "
+ from + " to " + to + ".");
long difference = output.getTime() - startTime.getTime();
System.out.println("Result: " + sdf.format(output) + ". Change ("
+ difference / 1000 / 60 / 60 + " hour).\n");
}
// wrapper around joda test
private void timeTestJoda(Date startTime, String from, String to) {
Date output = convertJodaOld(startTime, TimeZone.getTimeZone(from),
TimeZone.getTimeZone(to));
print(startTime, "joda", from, to, output);
}
// wrapper around java test
private void timeTestJava(Date startTime, String from, String to) {
Date output = convertJava(startTime, TimeZone.getTimeZone(from),
TimeZone.getTimeZone(to));
print(startTime, "java", from, to, output);
}
// Joda implementation, works before and after DST change, but not during
// the period from 2am-7am UTC on the day of the change
public Date convertJodaOld(Date dt, TimeZone from, TimeZone to) {
DateTimeZone tzFrom = DateTimeZone.forTimeZone(from);
DateTimeZone tzTo = DateTimeZone.forTimeZone(to);
Date utc = new Date(tzFrom.convertLocalToUTC(dt.getTime(), false));
Date convertedTime = new Date(tzTo.convertUTCToLocal(utc.getTime()));
return convertedTime;
}
// Java implementation. Works.
public Date convertJava(Date dt, TimeZone from, TimeZone to) {
long fromOffset = from.getOffset(dt.getTime());
long toOffset = to.getOffset(dt.getTime());
long convertedTime = dt.getTime() - (fromOffset - toOffset);
return new Date(convertedTime);
}
}
谢谢!
最佳答案
不要使用“美国/亚利桑那”,它已经过时了。
使用“美国/凤凰城”
'US/Pacific' 也是如此,请改用 'America/Los_Angeles'。
关于java - 非 DST 时区的 Joda 时间转换不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5148050/
在 Windows 世界中,什么是正确的名称。具有导出函数的老式 C++ DLL?不是 COM DLL,也不是 .NET DLL。我们以前通过调用 LoadLibrary() 和 GetProcAdd
目前我正在使用javaEE7,我有一个场景如下。在我的 JSF Web 应用程序中,我有一个事件监听器(不是 JSF 事件),当事件调用时,它会执行某些操作,然后将这些信息更新到我的 Web 应用程序
这不是 AJAX 请求/响应回调问题... 我正在使用 Dojo 1.5 构建网格。我正在尝试 dojo.connect具有功能的扩展/收缩按钮。我的问题是 grid.startup()在创建实际 D
非 Webkit Opera 是 very specific在某些功能中,因此通常通过 JavaScript 检测到 the following way . 但是,Opera Next 几乎是 Goo
我已查看以下链接中给出的所有日志,但未能找到 IP 地址: https://developer.couchbase.com/documentation/server/3.x/admin/Misc/Tr
我有一个命令行程序,它根据一组源文件生成一个我想在我的 Android gradle 构建 (A) 中使用的 jar 文件。这个命令行程序只是将一个 jar 文件存储在磁盘上的一个目录中。 我如何创建
下面的 htaccess 命令将所有非 www 转移到 http www RewriteEngine On RewriteCond %{HTTP_HOST} !^www\. RewriteRule ^
我正在使用自定义链接器脚本将内核镜像分为两部分。第一个是普通代码和数据,第二个是初始化代码和不再需要时将被丢弃的数据。初始化部分也不像内核本身那样在地址空间之间共享,因此如果 fork() 仍然存在(
这个问题在这里已经有了答案: Several unary operators in C and C++ (3 个答案) What is the "-->" operator in C++? (29
假设我有一个类设置如下: class A { public: virtual void foo() { printf("default implementation\n"); } }; c
#include using namespace std; int main(int argc, char *argv[]) { int i=-5; while(~(i)) {
近期,百度搜索引擎变化无常,很多企业站、行业站、门户站、论坛等站点遭到了降权,特别是比比贴分类信息网直接遭到了拔毛,这对于广大站长来说是一种打击,也是各个企业、行业的打击。 至今,很多网站已经恢复
我现在正在使用 IBM TPM v1332 + IBM TSS v1470 并尝试将一些基本关键字/密码存储到 TPM 上的非 volatile 内存中。我找到了两种方法。一种是创建一个密封对象并使用
我的 PHP 脚本中有一个正则表达式,如下所示: /(\b$term|$term\b)(?!([^)/iu 这与 $term 中包含的单词匹配,只要前后有单词边界并且它不在 HTML 标记内即可。 但
我想显示用户名称地址(请参阅 www.ipchicken.com ),但我唯一能找到的是 IP 地址。我尝试了反向查找,但也没有用: IPAddress ip = IPAddress.Parse(th
只有 UI 线程能够显示到屏幕上,还是其他线程也可以这样做? 最佳答案 不,您只能直接从 UI 线程访问 UI,但您可以编码来自其他线程的结果,例如使用 Control.Invoke 或 contro
我正在使用现代 Excel 滚动条(不是旧的 ActiveX 类型,即开发人员 > 插入 > 表单控件 > 滚动条)并且想检测它的值何时更改。我找不到有关此类对象的更改事件的任何信息。您可以在单击时分
当我使用这段代码时 IE 6 确实正确使用了指定的样式表,但所有其他浏览器在应该使用基本上声明的样式表时会忽略这两种样式表,如果您不是 IE,请使用此样式表。 有什么想法吗? 最佳答案 n
我想指定 2 mssql 表之间的关系。 付款类别和付款。 paymentcategory.id 加入 payout.category 列。 在 payout.json 模型中 我指定为外键:id,
我正在尝试制作非 volatile UDF,但似乎不可能。因此,这是我非常简单的test-UDF: Option Explicit Dim i As Integer Sub Main() i = 0
我是一名优秀的程序员,十分优秀!