2

我有一个日期字符串1/1/1970 8:00 AM

正确的毫秒应该是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()
4

3 回答 3

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/MMMM/dd,具体取决于您的日期将采用的格式 - 我们无法从“01/01”中分辨出来。请注意时区和语言环境的显式设置。

于 2012-10-25T18:04:08.303 回答
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
于 2012-10-25T18:17:54.257 回答
0

java.time

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

另外,下面引用的是来自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

An代表UTCInstant时间线上的一个瞬时点。

从Trail: Date Time了解有关现代日期时间 API 的更多信息。


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

于 2021-07-17T14:23:27.800 回答