在EpochMilli和ofEpochSecond之间切换

时间:2018-03-20 21:51:43

标签: java java-8

在我的应用程序中,第三方API返回时间戳中的时间戳。

有时它以秒为单位返回纪元时间,有时以毫秒为单位返回未确认。我的应用程序使用下面的代码 将它转换为java日期并显示给用户,但是当我以毫秒为单位收到时间时,它会在一年内失败。

    String time = "1519377196185"; //Time in miliseconds
    //String time = "1521575819"; //Time in seconds.
    String timeZone = "US/Pacific";
    long epochdate = Long.parseLong(time);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy hh:mm a");
    LocalDateTime date34 =
                Instant.ofEpochSecond(epochdate)
              .atZone(ZoneId.of(timeZone))
              .toLocalDateTime();
    String date = date34.format(formatter).toString();
    System.out.println("date : " + date);

如果我使用Instant.ofEpochMilli(epochdate)毫秒,那么它工作正常。所以我的问题是我怎么知道即将到来的时间戳是以毫秒或秒为单位所以在此基础上我会在ofEpochMilliofEpochSecond之间切换

4 个答案:

答案 0 :(得分:0)

一个简单(临时,类似)解决方案就是检查time String的长度。如果长度等于13,则表示毫秒。在1 ms 2286-11-20T17:46:39.999Z之后,这将是真实的,这是很长一段时间。以秒为单位的时间需要更长的时间才能达到13的长度。

答案 1 :(得分:0)

您可以通过以秒为单位将纪元转换为纪元(以毫秒为单位)并仅对{8}同时应用Instant.ofEpochMilli()来解决此问题。

String time = "1519377196185"; //Time in miliseconds or seconds

if(time.length() == 10) { // length of epoch in seconds is 10
    time = time + "000";
}

String timeZone = "US/Pacific";

long epochdate = Long.parseLong(time);

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy hh:mm a");

LocalDateTime date34 = Instant.ofEpochMilli(time)
                              .atZone(ZoneId.of(timeZone))
                              .toLocalDateTime();

String date = date34.format(formatter).toString();

System.out.println("date: " + date);

答案 2 :(得分:0)

检查字符串输入的长度

如Jacob G. his Answer所述,检查长度。

String input = "1519377196185";  // Milliseconds since epoch.
//String input = "1519377196" ;  // Seconds since epoch.
Instant instant = null;
int length = input.length();
switch ( length )
{
    case 13:
        instant = Instant.ofEpochMilli( Long.parseLong( input ) );
        break;
    case 10:
        instant = Instant.ofEpochSecond( Long.parseLong( input ) );
        break;
    default:
        throw new IllegalStateException( "Unexpected length of input text for count-from-epoch number: " + input + ". Message # 2188d054-5720-4393-9b18-829913d7ba1c." );
}
System.out.println( input + " ➞ " + instant.toString() );  // Generate a String representing textually the value of the `Instant` object.
  

1519377196185➞2018-02-23T09:13:16.185Z

或者:

  

1519377196➞2018-02-23T09:13:16Z

ZonedDateTime

要从Instant中的UTC移动到某个特定时区,请提供时区(ZoneId)的上下文以获取ZonedDateTime对象。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
  

zdt.toString():2018-02-23T10:13:16.185 + 01:00 [非洲/突尼斯]

LocalDateTime - 这里不合适

要使用 LocalDateTime类是错误的类,如问题所示。这个类故意缺乏任何时区概念或从UTC偏移。所以它代表片刻,并且时间轴上的一个点。此类表示在大约26-27小时范围内的潜在时刻。

仅在区域/偏移未知(可怕的情况)或需要无限期值时使用LocalDateTime,例如“2018年12月25日第一时间的圣诞节开始”。

答案 3 :(得分:0)

年度偏差

我会尝试首先将日期解析为秒,因为如果日期是毫秒,则年份将是非常大的(在这种情况下为50000),那么如果年份不大于定义的年份偏差(例如, 3000),返回该日期,否则日期以毫秒返回。

getZonedDateTime("1519377196185"); // 2018-02-23T01:13:16.185-08:00[US/Pacific]
getZonedDateTime("1521575819"); // 2018-03-20T12:56:59-07:00[US/Pacific]

使用功能打印:

1970-01-01T00:00:00Z

错误保证金

您决定使用的任何方法都可能出错,并且日期转换不正确,特别是当日期以毫秒为单位并且距离纪元3000太近时。

使用Instant.ofEpochMilli(LocalDateTime.of(3000, 1, 1, 0, 0) // year = 3000 .toEpochSecond(ZoneOffset.UTC)); // 1971-01-12T04:48:00Z 年份偏差的保证金误差为:

  • 日期最初为毫秒,范围为 1970-01-01T00:00:00Z ,直至 1971-01-12T04:48:00Z
    • 将被视为以秒为单位的日期
  • 日期最初为且日期相等或 3000-01-01T00:00:00Z 之后(普通应用中的日期不大)
    • 将被视为以毫秒为单位的日期

以毫秒为单位计算错误范围

您可以使用以下命令计算最初的日​​期误差范围(以毫秒为单位):

if (custDoe_TextField.isEditable()) {//isEditable returns boolean
    //do something here
}