java/android中的时区澄清



我有下面的代码

public Long getEpochTime(String dateToGetItsEpoch) throws ParseException
{
    TimeZone timeZone = TimeZone.getTimeZone("UTC");
    final String REQUEST_DATE_FORMAT = "dd/MM/yyyy h:m";
    DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
    Date localDate = format.parse(dateToGetItsEpoch);
    Calendar cal = Calendar.getInstance(timeZone);
    cal.setTime(localDate);
    format.setTimeZone(timeZone);
    final String utcTime = format.format(cal.getTime());
    Date d = cal.getTime();
    return d.getTime();
}

如果我将设备的区域设置更改为任意设置,我总是将UTC时间作为返回值。哪一个是正确的,但是我想知道这是怎么发生的?设备如何知道我给它的日期是哪个时区,以便进行相应的计算?

Date根本没有时区。SimpleDateFormat作为解析和格式化的默认值;CCD_ 3也这样做;CCD_ 4没有。

给定以下操作序列:

TimeZone timeZone = TimeZone.getTimeZone("UTC");
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date localDate = format.parse(dateToGetItsEpoch);
Calendar cal = Calendar.getInstance(timeZone);
cal.setTime(localDate);
format.setTimeZone(timeZone);
final String utcTime = format.format(cal.getTime());

您最初使用设备的默认时区解析字符串,然后以UTC格式格式化字符串。注意,Calendar部分在这里是不相关的——使用会得到相同的结果

TimeZone timeZone = TimeZone.getTimeZone("UTC");
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date date = format.parse(dateToGetItsEpoch);
format.setTimeZone(timeZone);
final String utcTime = format.format(date);

请注意,我个人建议在Java中尽可能使用Joda Time进行日期/时间工作。它是一个比Calendar/Date更干净的API。

java.time

Jon Skeet的答案是正确的。这里有一些代码更新为使用现代的java.time类,这些类取代了麻烦的遗留日期-时间类。

格式化模式

定义一个格式模式以匹配您的输入。

顺便说一句,你的格式选择不好。相反,我建议使用标准ISO 8601格式,该格式旨在将日期时间值作为文本进行交换。

12小时与24小时

您的输入数据或格式模式存在缺陷。您使用了小写h,意思是12小时时钟中一个小时的一到两位数字(而不是24小时时钟,大写HHH)。因此,除非添加一些AMPM的指示符,否则您的输入毫无意义。我认为您在问题代码中错误地忽略了这一点。

Locale locale = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu h:m a" ).withLocale( locale ) ;

LocalDateTime

将此类字符串解析为LocalDateTime对象,因为它们缺少预期时区或UTC偏移量的指示符。

String input = "23/01/2020 4:5 PM" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

ldt.toString():2020-01-23T16:05

力矩

我们在上面获得的LocalDateTime对象不代表一个时刻,而不是时间线上的一个点。我们的时间是23日下午4点左右。但我们不知道这是东京、图卢兹还是托莱多的下午4点——所有这些时间相隔几个小时。

为了确定一个时刻,我们必须确切地知道预定的时区。然后将该区域应用为ZoneId以获得ZonedDateTime。那我们马上就到了。

Locale不是时区

我的设备的区域设置为任何

Locale与时区无关。Locale用于本地化生成的表示日期-时间对象的文本。

要本地化,请指定:

  • CCD_ 21来确定字符串的长度或缩写
  • Locale确定:
    • 人类语言,用于日名、月名等的翻译
    • 文化规范决定缩写、大写、标点符号、分隔符等问题

示例:

Locale l = Locale.CANADA_FRENCH ;   // Or Locale.US, Locale.JAPAN, etc.
DateTimeFormatter f = 
    DateTimeFormatter
    .ofLocalizedDateTime( FormatStyle.FULL )
    .withLocale( l )
;
String output = myZonedDateTime.format( f );

你可以让一位来自魁北克的工程师使用Locale.CANADA_FRENCH进行人类语言和文化规范,但在日本访问时,他使用Asia/Tokyo时区进行预约。

ZonedDateTime

返回到您的LocalDateTime对象。如果你确定它代表的是突尼斯挂钟时间中的一个时刻,那么应用Africa/Tunis时区。

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

你问:

设备如何知道我给它的日期是哪个时区,以便进行相应的计算?

你使用了糟糕的日期-时间类,这些类没有考虑到日期-时间的概念,没有时区或UTC偏移的指标。因此,从技术上讲,你的代码是一团糟,是一次黑客攻击,在JodaTime及其继任者java.Time之前的日子里是不可避免的。

我建议花费no的努力来尝试理解CCD_;CCD_ 29。只需继续使用java.time,这是业界领先的日期-时间处理框架。

相关内容

  • 没有找到相关文章

最新更新