使用Date.parse(dateString)给定日期的Millis是错误的

时间:2012-10-25 18:02:19

标签: java date milliseconds

我的日期字符串为1/1/1970 8:00 AM

正确的millis应为8 hours * 60 minutes per hour * 60000 milliseconds per minute = 28800000

但是,使用Date.parse(dateString)会返回50400000

我不理解什么?

修改

我最初尝试使用date.getTime();

这是我的原始代码:

SimpleDateFormat dateFmt = new SimpleDateFormat("MM/dd/yyyy h:mm a");
dateFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
StringBuilder sb = new StringBuilder();                     
sb.append(month).append("/");
sb.append(day).append("/");
sb.append(year).append(" ");
sb.append(pad(hour)).append(":");
sb.append(pad(minute)).append(" ");;
sb.append(ampm);
Date date = new Date();

date = dateFmt.parse(sb.toString());

date.getTime()

3 个答案:

答案 0 :(得分:7)

这几乎肯定是问题所在:

  

如果未指定时区,则假定为本地时区。

我的猜测是你所处的时区是在Unix时代的UTC-6,所以当地时间早上8点是UTC时间下午2点。

然后,当有更好的替代方法(SimpleDateFormat,允许您设置时区)可用时,使用弃用方法存在更基本的问题。不推荐使用原因的方法。你不应该只使用弃用的方法,否则你会继续遇到这样的事情。

事实上,如果可能的话,最好使用Joda Time - 但至少远离Date中弃用的方法。

示例代码:

SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy h:mm aa", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
long millis = format.parse(text).getTime();

您可能希望将dd/MM更改为MM/dd,具体取决于您的日期格式 - 我们无法从“01/01”判断出来。请注意时区和区域设置的显式设置。

答案 1 :(得分:1)

因为您当地的时区。使用带有时区的简单日期格式,如下所示,以获得UTC时区所需的值:

    DateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
    String dateS = "1/1/1970 8:00 AM";
    format.setTimeZone(TimeZone.getTimeZone("UTC"));  
    format.setLenient(true);
    Date date = format.parse(dateS);
    System.out.println(date.getTime()); //<-- prints 28800000

或更紧凑:

    DateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
    format.setTimeZone(TimeZone.getTimeZone("UTC"));  
    Date date = format.parse("1/1/1970 8:00 AM");
    System.out.println(date.getTime());  //<-- prints 28800000

答案 2 :(得分:0)

java.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*

另外,下面引用的是来自 home page of Joda-Time 的通知:

<块引用>

请注意,从 Java SE 8 开始,要求用户迁移到 java.time (JSR-310) - JDK 的核心部分,取代了该项目。

使用 java.time(现代日期时间 API)的解决方案:

您不需要形成字符串:您可以使用 LocalDateTime#of 创建 LocalDateTime 的实例,该实例可以按顺序转换为 Instant获取 Unix 纪元的毫秒数。

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

public class Main {
    public static void main(String[] args) {
        int year = 1970, month = 1, dayOfMonth = 1, hour = 8, minute = 0;
        LocalDateTime ldt = LocalDateTime.of(year, month, dayOfMonth, hour, minute);
        Instant instant = ldt.toInstant(ZoneOffset.UTC);
        System.out.println(instant.toEpochMilli());
    }
}

输出:

28800000

ONLINE DEMO

如果您已经有给定格式的日期时间字符串:

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/u h:m a", Locale.ENGLISH);
        String strDateTime = "1/1/1970 8:00 AM";
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);

        Instant instant = ldt.toInstant(ZoneOffset.UTC);
        System.out.println(instant.toEpochMilli());
    }
}

输出:

28800000

ONLINE DEMO

Instant 表示 UTC 中时间轴上的瞬时点。

Trail: Date Time 了解有关现代 Date-Time API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project