使用 java 7 来回将毫秒转换为日期字符串

Convert milliseconds to date string back and forth using java 7

我有以下代码,它使用了类似问题中讨论的所有建议。

public class DateUtils {
static String secondsToDate(String seconds) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(Long.parseLong(seconds) * 1000);
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DAY_OF_MONTH);

    return String.format("%d-%d-%d", year, month, day);
}

static String dateToSeconds(String date) {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    try {
        Date parsed = format.parse(date);
        long timeInMillis = parsed.getTime();
        return Long.toString(timeInMillis / 1000);
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return null;
}

public static void main(String[] args) {
    String timestamp = "1409515200";
    String date = secondsToDate(timestamp);
    String timestamp2 = dateToSeconds(date);
    System.out.printf("%s  %s", timestamp, timestamp2);
}
}

代码的结果:

1409515200  1406836800

如您所见,来回转换不起作用。怎么了?

你的问题是四舍五入。在第一种方法中,您将时间戳(即从 1970 年开始的 毫秒 的数量)转换为日期。您现在只获取日期,丢弃小时、分钟、秒和毫秒并将其转换回来。这意味着您将始终拥有丢弃的数量差异(在 00:00:00:000 的 0 和 23:59:59:999 的 86400000 之间)。要修复它,只需更改您的日期格式以包含精确到毫秒的小时数。

正确,应该接受。

一些进一步的提示……

使用日期时间 classes 作为日期时间值,而不是字符串。使用日期时间对象执行业务逻辑,并在代码中传递此类对象而不是字符串。

避免将日期时间跟踪为纪元计数。当您确实需要序列化为文本时,请使用 ISO 8601 标准定义的明确且易于阅读的格式,例如 2016-05-09T16:47:54Z.

您正在使用旧的、麻烦的遗留 classes,它们已被 java.time framework built into Java 8 and later. Much of that functionality has been back-ported to Java 6 & 7 in the ThreeTen-Backport project, and further adapted for Android in the ThreeTenABP 项目取代。

使用 java.time classes 会让你的工作更轻松,你的代码更容易理解,不太可能遇到问题中出现的混乱。

Instant 是 UTC 时间轴上的一个时刻,分辨率为纳秒。 class 提供了一个方便的工厂方法 ofEpochSecond,因此无需乘以一千毫秒。

String input = "1409515200";
long seconds = Long.parseLong( input );
Instant instant = Instant.ofEpochSecond( seconds );

得到wall-clock time for some locality, assign a time zone to get a ZonedDateTime.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

要生成标准 ISO 8601 格式的字符串,请调用 toString。请注意,此方法扩展了该格式以在方括号中附加时区名称。例如,2007-12-03T10:15:30+01:00[Europe/Paris].

String output = zdt.toString();

要获取问题中的仅限日期,请提取一个 LocalDate 对象。

LocalDate localDate = zdt.toLocalDate();

从那里您可以确定一天的第一时刻。第一时刻并不总是一天中的时间 00:00:00.0,因此让 java.time 确定。

ZonedDateTime zdtStartOfDay = localDate.atStartOfDay( zoneId );

要获得问题中看到的两个长整数秒数,从我们的每个 ZonedDateTime 对象中提取一个 Instant,并询问自纪元以来的秒数。请注意,您可能会丢失数据,因为 ZonedDateTime/Instant 对象可以存储分辨率高达纳秒的值。从纪元开始要求整秒的调用意味着任何一小部分秒都被截断了。

long seconds1 = zdt.toInstant().getEpochSecond();
long seconds2 = zdtStartOfDay.toInstant().getEpochSecond();