为什么util.Date转发日期而不是减去它?

时间:2017-06-15 06:40:47

标签: java timestamp java.util.date

我想在IST中将UTC转换为Java纪元 但不是从IST减去5.30小时,而是在IST

中增加5.30
public static long convertDateToEpochFormat(String date) {
    Date convertedDate = null;
    try {
        LOGGER.info(date);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
        LOGGER.info(date);
        convertedDate = formatter.parse(date);
        LOGGER.info(convertedDate);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return convertedDate.getTime() / 1000L;
}

我获得的日志声明是:

2017-01-01 00:00:00
2017-01-01 00:00:00
Sun Jan 01 05:30:00 IST 2017

由于UTC转换,理想情况下应该是Dec 31 18:30:00。

谁能告诉我什么错了?

2 个答案:

答案 0 :(得分:3)

TL;博士

  

为什么util.Date转发日期而不是减去日期?

因为印度时间是提前的UTC,而不是落后。

Instant.parse(
    "2017-01-01 00:00:00".replace( " " , "T" ) + "Z" 
).atZone(
    ZoneId.of( "Asia/Kolkata" )
).toString()
  

2017-01-01T05:30 + 05:30 [亚/加尔各答]

使用java.time

你正在使用现在遗留下来的麻烦的旧日期时间类,取而代之的是java.time类。

ISO 8601

您的输入字符串几乎采用标准ISO 8601格式。要完全遵守,请使用T替换中间的空格。解析/生成字符串时,java.time类使用标准格式。因此无需指定格式化模式。

String input = "2017-01-01 00:00:00".replace( " " , "T" ) ;

如果该输入用于表示UTC中的时刻,则附加ZZulu的缩写,表示UTC。

String input = "2017-01-01 00:00:00".replace( " " , "T" ) + "Z" ;  // Assuming this input was intended to be in UTC.
  

2017-01-01T00:00:00Z

如果可能,在将日期时间值序列化为字符串时,首先使用ISO 8601格式。

Instant

将输入字符串解析为Instant,在时间轴上以UTC为单位,分辨率为纳秒。

Instant instant = Instant.parse( input ) ;
  

instant.toString():2017-01-01T00:00:00Z

ZonedDateTime

您似乎希望将此值调整为印度时间。应用ZoneId获取ZonedDateTime

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
  

zdt.toString():2017-01-01T05:30 + 05:30 [亚洲/加尔各答]

请参阅此code run live at IdeOne.com

印度时间提前 UTC

你的问题预计印度时间会倒退,落后于UTC值。这毫无意义。印度时间未来,而不是UTC。美洲在 UTC后面有时区,因为它们位于西侧。格林威治的Prime Meridian以东是UTC的提前。在现代,ISO 8601和大多数其他协议使用 plus 符号标记此类偏移:+05:30。请注意,一些旧协议则相反(使用负号)。

午夜UTC = 5:30 AM印度

午夜时分,在午夜时分00:00:00在Prime Meridian,同时在印度早上五点半。

因此,所有这三个代表相同的同时时刻,时间轴中的相同点:

  • 2017-01-01T00:00:00Z
  • 2017-01-01T05:30+05:30[Asia/Kolkata]
  • 2016-12-31T16:00-08:00[America/Los_Angeles]

避免从纪元算起

在Java代码中,使用日期时间对象传递日期时间值,特别是java.time对象。在Java代码之外传递日期时间值时,使用实际的ISO 8601格式序列化为字符串。

依赖于从纪元开始的整数计数值令人困惑,难以调试,人类无法阅读,并且会导致挫折和错误(更糟糕的是:未观察到的错误)。

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:1)

The answer by Basil Bourque is not only correct, it is also very informative. I have already upvoted it. I’ll try just a little bit of a different angle.

As I understand your question, your date-time string 2017-01-01 00:00:00 should be interpreted in IST, AKA Asia/Kolkata time, and you want to convert it to seconds (not milliseconds) since the epoch. And you are asking why you are getting an incorrect result.

I think the answer is rather banal: When the date-time string is in India time, you should not set UTC time on the formatter you use for parsing it. This is sure to get an incorrect result (if you were to format the date-time into UTC, you would do well in setting UTC as time zone on the formatter used for formatting, but this is a different story).

I agree with Basil Bourque that you should avoid the outdated classes Date and SimpleDateFormat. So here’s my suggestion (assuming you do need epoch seconds and cannot use an Instant as Basil Bourque recommends).

private static DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");

public static long convertDateToEpochFormat(String date) {
    return LocalDateTime.parse(date, parseFormatter)
            .atZone(ZoneId.of("Asia/Kolkata"))
            .toInstant()
            .getEpochSecond();
}

This will convert your example string into an instant of 2016-12-31T18:30:00Z and return 1483209000. Please check for yourself that it is correct.

I have been assuming all the way that by IST you meant Indian Standard Time. Please be aware that three and four letter time zone abbreviations are ambiguous. For example, my JVM thinks that IST means Israel Standard Time. If you intended the same, please substitute Asia/Jerusalem for Asia/Kolkata. If you meant Irish Standard Time (another recognized/semi-official interpretation), please use Europe/Dublin. You will of course get different output in each case.