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

时间:2016-05-09 16:47:56

标签: date 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

正如您所看到的,来回转换不起作用。怎么了?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

answer by Aurasphere是正确的,应该被接受。

一些进一步的提示......

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

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

您正在使用旧的麻烦遗留类,这些遗留类已被Java 8及更高版本中内置的java.time框架取代。大部分功能已经被移植到Java 6& ThreeTen-Backport项目中的7,并在ThreeTenABP项目中进一步适用于Android。

使用java.time类将使您的工作更轻松,您的代码更容易理解,更不可能遇到问题中看到的混淆。

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

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

要获取某个地区的wall-clock time,请指定一个时区以获得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 );

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

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