我正在开发一个从Google TimeZone API
获取数据的应用程序。
简单地说,我有时间在地球上所需的地方毫秒。
例如:1504760156000
它显示在伦敦的日期时间
Thu Sep 07 2017 09:55:56
我在UTC的TimeZone +05:00
中如果我操纵1504760156000
这些毫秒,它会显示如下所示的整个日期时间:
Thu Sep 07 2017 09:55:56 GMT + 0500(巴基斯坦标准时间)
但我想表明:
Thu Sep 07 2017 09:55:56 GMT + 0100(英国夏令时间)
问题的道德:我有正确的伦敦日期和时间,但能够在不更改时间的情况下显示/更改TimeZone,因为伦敦的时间是正确的。
已更新
得到一些评论后。在我的例子中,你没有让我到这里来。
假设我在巴基斯坦,时间在这里1:55 PM
所以我通过我的申请向GOOGLE API询问了我在伦敦的时间。谷歌API告诉我在伦敦的时间是1504760156000
(上午9:55),如果我将这些毫秒转换为Date
对象,它会打印出如下所示:
Date date =new Date(1504760156000)
Thu Sep 07 2017 09:55:56 GMT + 0500(巴基斯坦标准时间)
它将根据我的Local TimeZone操纵它,但我想要下面的结果
Thu Sep 07 2017 09:55:56 GMT + 0100(英国夏令时间)
更新2
由于Google时区API需要以秒为单位的时间戳UTC,我以UTC为单位准备了以秒为单位的时间戳
"https://maps.googleapis.com/maps/api/timezone/json?location="+Latitude +","+Longitude+"×tamp="+currentTimeUTCinSeonds+"&key="API KEY"
Google API使用以下针对伦敦的JSON回复我。
{
"dstOffset" : 3600,
"rawOffset" : 0,
"status" : "OK",
"timeZoneId" : "Europe/London",
"timeZoneName" : "British Summer Time"
}
根据文件:
计算当地时间
给定位置的本地时间是时间戳的总和 参数,以及结果中的dstOffset和rawOffset字段。
我总结结果timestamp+rawoffset+dstoffset*1000='1504760156000'
(在我尝试时)
项目代码
Long ultimateTime=((Long.parseLong(timeObject1.getDstOffset())*1000)+(Long.parseLong(timeObject1.getRawOffset())*1000)+timestamp*1000);
timeObject1.setTimestamp(ultimateTime); //its Sime POJO object to save current time of queried Location
Date date=new Date(ultimateTime);
date1.setText("Date Time : "+date);
正如我所说,我在当地时区操纵结果所以当时它给了我以下结果:
Thu Sep 07 2017 09:55:56 GMT + 0500(巴基斯坦标准时间)
但我知道API给了我正确的时间。问题是与UTC的本地偏移。我只想将GMT+0500
更改为GMT+0100
答案 0 :(得分:3)
时间戳表示自纪元以来经过的时间的“绝对”值。例如,您的currentTimeUTCinSeconds
表示自UTC时间为unix时期(1970-01-01T00:00Z
或 1月1日 st 1970年午夜时的秒数 )。 Java API通常使用自纪元以来的毫秒数。
但这个概念是一样的 - 这些价值观是“绝对的”:无论他们身在何处,他们对世界上的每个人都是一样的。如果世界不同地区的2个人(在不同的时区)同时获得当前时间戳,他们将获得相同的数字。
在不同的时区,有相同的数字代表不同的本地日期和时间。
例如,您正在使用的时间戳,对应于9月7日 th 2017 08:55:56 UTC,其值为1504774556(自纪元以来的秒数)。这个数字相当于伦敦的09:55,卡拉奇的13:55,东京的17:55,依此类推。 更改此号码会更改每个人的当地时间 - 无需操纵它。
如果您想获得代表此瞬间的java.util.Date
,请执行以下操作:
int currentTimeUTCinSeconds = 1504774556;
// cast to long to not lose precision
Date date = new Date((long) currentTimeUTCinSeconds * 1000);
此日期将保留值1504774556000(自纪元以来的毫秒数)。该值对应于伦敦的09:55,卡拉奇的13:55和东京的17:55。
但打印此日期会将其转换为您的JVM默认时区(here是对Date::toString()
方法行为的一个很好的解释)。执行"Date Time : "+date
时,它会调用toString()
方法,结果是将日期转换为默认时区。
如果您想要特定格式和特定时区的日期,则需要SimpleDateFormat
。只打印日期(使用System.out.println
或记录日期)将无效:您无法更改日期对象本身的格式,因为Date
has no format。
我还使用java.util.Locale
来指定月份和星期几必须是英语。如果你没有指定语言环境,它将使用系统默认值,并且不能保证始终为英语(即使在运行时也可以更改,因此最好始终指定语言环境):
// use the same format, use English for month and day of week
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (zzzz)", Locale.ENGLISH);
// set the timezone I want
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
// format the date
System.out.println(sdf.format(date));
输出将是:
Thu Sep 07 2017 09:55:56 GMT + 0100(英国夏令时间)
请注意,我不需要操纵时间戳值。我不使用谷歌API,但我认为他们的解释太混乱了,上面的代码实现了相同的结果,并没有更少的复杂性。
在您的具体情况下,您可以:
date1.setText("Date Time : "+sdf.format(date));
旧类(Date
,Calendar
和SimpleDateFormat
)有lots of problems和design issues,它们将被新API取代。< / p>
在Android中,您可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。为了使其有效,您还需要ThreeTenABP(更多关于如何使用它here)。
要从时间戳获取日期,我使用org.threeten.bp.Instant
和org.threeten.bp.ZoneId
将其转换为时区,创建org.threeten.bp.ZonedDateTime
。然后我用org.threeten.bp.format.DateTimeFormatter
格式化它:
int currentTimeUTCinSeconds = 1504774556;
// get the date in London from the timestamp
ZonedDateTime z = Instant.ofEpochSecond(currentTimeUTCinSeconds).atZone(ZoneId.of("Europe/London"));
// format it
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss 'GMT'XX (zzzz)", Locale.ENGLISH);
System.out.println(fmt.format(z));
输出相同:
Thu Sep 07 2017 09:55:56 GMT + 0100(英国夏令时间)
在你的情况下,只需:
date1.setText("Date Time : "+fmt.format(z));