我有以下代码,它使用了类似问题中讨论的所有建议。
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
正如您所看到的,来回转换不起作用。怎么了?
答案 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();