尝试使用JSR 310在时区之间转换毫秒日期时间值。使用传统API需要处理毫秒值。在我的情况下,它在本地和UTC / GMT之间,但我希望它是完全相同的代码,独立于所涉及的源和目标时区。这是我的小测试程序。它被配置为在最后一次本地DST更改周围的小时内迭代。输出是错误的,所以我认为UTCtoLocalMillis是错误的,但可能我的测试方法也存在问题。错误输出的意思是,对于我的时区,应该减去几小时以获得UTC,但代码实际上增加了几个小时。其次,DST点击的时间也是一小时。
我首先获取本地时区,然后将其重置为UTC,这样Date()。toString()在创建输出时不会执行任何转换。
我想要的是创建一个花费时间(以毫秒为单位)的方法,一个源ZoneID和一个目标ZoneID,并使用新的JSR 310 API返回转换的毫秒数。
public class Test {
static int DAYS_OFFSET_TO_BE_BEFORE_DST_CHANGE = -16;
static TimeZone UTC_TZ = TimeZone.getTimeZone("UTC");
static TimeZone LOCAL_TZ = TimeZone.getDefault();
static ZoneId UTC_ID = ZoneId.of(UTC_TZ.getID());
static ZoneId LOCAL_ZONE_ID = ZoneId.of(LOCAL_TZ.getID());
static long UTCtoLocalMillis(final long utcMillis) {
final Instant instant = Instant.ofEpochMilli(utcMillis);
final ZonedDateTime before
= ZonedDateTime.ofInstant(instant, UTC_ID);
final ZonedDateTime after
= before.withZoneSameLocal(LOCAL_ZONE_ID);
return after.toInstant().toEpochMilli();
}
public static void main(final String[] args) {
TimeZone.setDefault(UTC_TZ);
System.out.println("LOCAL_TZ: " + LOCAL_TZ.getDisplayName());
final Calendar cal = Calendar.getInstance(LOCAL_TZ);
cal.add(Calendar.DATE, DAYS_OFFSET_TO_BE_BEFORE_DST_CHANGE);
final Date start = cal.getTime();
// DST Change: Sunday, 31 March 2013 01:59:59 (local time)
final long oneHour = 3600000L;
for (int i = 0; i < 12; i++) {
final Date date = new Date(start.getTime() + i * oneHour);
System.out.println("UTC: " + date + " toLocal: "
+ new Date(UTCtoLocalMillis(date.getTime())));
}
}
}
答案 0 :(得分:3)
我想要的是创建一个花费时间(以毫秒为单位)的方法,一个源ZoneID和一个目标ZoneID,并使用新的JSR 310 API返回转换的毫秒数。
您的要求似乎很困惑。时间API中通常提到的“毫秒”值是纪元 - 毫秒,即1970-01-01T00:00Z的毫秒数。 millis值始终相对于UTC。虽然有一个“本地millis”的概念,它从来没有真正使用过。特别是,java.util.Date构造函数采用了epoch-millis。
因此,代码new Date(UTCtoLocalMillis(date.getTime()))
基本上没有意义。
答案 1 :(得分:1)
Instant // Represent a moment in UTC with a resolution of nanoseconds.
.ofEpochMilli( utcMillis ) // Parse a count of milliseconds since epoch of 1970-01-01T00:00:00Z.
.atZone( // Adjust from UTC to some time zone.
ZoneId.of( "Pacific/Auckland" )
)
Answer by JodaStephen是正确的。没有“ LocalMillis”之类的东西。您似乎有一些概念上的误解。这是可以理解的,因为日期时间工作出奇的棘手。
提示:学会在UTC中思考和工作。作为程序员或管理员,请忘记您自己的时区。可以将UTC视为一次真实的时间。各个时区只是变化而已。在UTC中进行日志记录,跟踪,数据存储和数据交换。将时区仅应用于向用户演示。在UTC和您自己的时区之间来回切换会驱动您前进。在桌上贴上第二个时钟,并将其设置为UTC;在工作时使用它。
另一个提示:在概念上关注时间轴。只有时间流。表示时间轴的主要方式是UTC。不同的时区只是单个时间轴上相同时刻的不同表示。
这是一些 java.time 代码示例。
使用新的JSR 310 API花费时间(毫秒),源ZoneID和目标ZoneID,并返回转换后的毫秒。
您不了解的部分是,“源ZoneID”始终为UTC ,以毫秒为单位。在UTC中绕过毫秒而不是 的任何人都没有经验,并寻求麻烦。
如果从1970-01-01T00:00:00Z UTC的1970年第一时刻的纪元参考起算,以毫秒为单位,则解析为Instant
。 Instant
代表UTC时刻。
Instant instant = Instant.ofEpochMilli( utcMillis ) ;
在String
中生成表示该Instant
中时刻的文本。默认情况下, java.time 类在解析/生成字符串时使用ISO 8601标准格式。末尾的Z
表示UTC,发音为“祖鲁语”。
String output = instant.toString() ;
2018-01-23T01:23:45.123456789Z
往另一个方向走...
long millisecondsFromEpoch = instant.toEpochMilli() ;
手握着Instant
,您可能想通过特定区域(时区)的人们所使用的挂钟时间的镜头来查看这一刻。 “挂钟时间”指的是一个人仰望挂在墙上的时钟和日历的日期和日期。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用3-4个字母的缩写,例如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
我们可以通过提取Instant
返回UTC。
Instant instant = zdt.toInstant() ; // Same moment, different wall-clock time.
最后一个提示:切勿使用Date
,Calendar
,SimpleDateFormat
或其他相关的旧式日期时间类。他们无休止地令人困惑和沮丧。仅使用 java.time 类。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:0)
Java文档确实非常清楚。
请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#currentTimeMillis%28%29
返回:
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC*.