java / android中的时区说明

时间:2013-08-28 08:24:05

标签: android date datetime timezone locale

我有以下代码

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时间作为返回值。这是正确的,但我想知道这是怎么回事?设备如何知道哪个时区是我给它的日期,以便相应地计算?

2 个答案:

答案 0 :(得分:2)

Date根本没有时区。 SimpleDateFormat作为解析和格式化的默认值; a Calendar也是; Date没有。

鉴于此操作顺序:

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);

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

答案 1 :(得分:1)

java.time

Answer by 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用于对生成的表示日期时间对象的文本进行本地化。

要本地化,请指定:

  • FormatStyle确定字符串应为多长或缩写。
  • 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偏移量指示符的日期时间概念。因此,从技术上讲,在 Joda-Time 及其后继者 java.time 之前的日子里,您的代码是一团糟,无法破解的事情。

我建议花费 no 努力了解DateCalendar的行为。只需继续使用业界领先的日期时间处理框架 java.time