如何在Java中获取您所在时区的当前日期和时间?

76

我的应用托管在伦敦服务器上。我在西班牙的马德里。因此,时区差是-2小时。

如何获取我的时区的当前日期/时间。

Date curr_date = new Date(System.currentTimeMillis());

e.g.

Date curr_date = new Date(System.currentTimeMillis("MAD_TIMEZONE"));

使用Joda-Time


DateTimeZone zone = DateTimeZone.forID("Europe/Madrid");
DateTime dt = new DateTime(zone);
int day = dt.getDayOfMonth();
int year = dt.getYear();
int month = dt.getMonthOfYear();
int hours = dt.getHourOfDay();
int minutes = dt.getMinuteOfHour();

可能是重复的问题:如何在Java中获取当前的UTC或GMT日期和时间? - Piskvor left the building
例如使用Joda-Time编写的代码来在不同时区之间进行转换,请参见我在问题“Java Convert GMT/UTC to Local time doesn't work as expected”(https://dev59.com/e2Ik5IYBdhLWcg3wU8yo#19378311)上的回答(https://dev59.com/e2Ik5IYBdhLWcg3wU8yo#19378311)。 - Basil Bourque
14个回答

103

Date 始终基于UTC或者是时间区域中立,具体取决于你的观点。 Date 仅仅表示一个时间点;它与时区无关,只是自Unix纪元以来的毫秒数。没有所谓的“本地实例Date” 的概念。使用 Date 结合Calendar 和/或TimeZone.getDefault() 来使用“本地”时区。使用 TimeZone.getTimeZone("Europe/Madrid") 获取马德里时区。

... 或者使用 Joda Time,它更容易理解,在Joda Time 中,您将使用DateTime 值,它是一个特定日历系统和时区的瞬间。

在Java 8中,您将使用java.time.ZonedDateTime,这是Java 8版本Joda Time的等效物。


5
当前日期的获取方法:Date currentDate = Calendar.getInstance(TimeZone.getDefault()).getTime() - user3132194
2
@user3132194:你认为这样做相比于 new Date() 会有什么好处? - Jon Skeet
2
@user3132194:那是一个非常糟糕的模板,不应该直接复制粘贴。与new Date()相比没有任何好处。如果你想要本地时间,就不应该使用Date。如果你认为你的代码比new Date()有用,我怀疑你可能误解了。 - Jon Skeet
你说得没错,new Date()java.util.Calendar.getInstance(java.util.TimeZone.getDefault()).getTime() 甚至 java.util.Calendar.getInstance(java.util.TimeZone.getTimeZone("Europe/Madrid")).getTime() 都是一样的。但不幸的是,你的答案是错误的。你能给我展示一个好的模板吗?似乎只有 Jesper 的答案是正确的。 - user3132194
@user3132194:不,我的答案不是错误的。我建议使用Joda Time(现在会说java.time)或Calendar。这两个都是可行的选项。我的答案哪里“错”了?我会编辑它以澄清,但仅仅声称它是错误的是不合适的,我认为。 - Jon Skeet
显示剩余2条评论

71

正如Jon Skeet所说,java.util.Date没有时区。一个Date对象表示自1970年1月1日UTC 12:00 AM以来的毫秒数,它不包含时区信息。

当您将Date对象格式化为字符串时,例如使用SimpleDateFormat,则可以在DateFormat对象上设置时区,以让它知道您想要显示日期和时间的时区:

Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

// Use Madrid's time zone to format the date in
df.setTimeZone(TimeZone.getTimeZone("Europe/Madrid"));

System.out.println("Date and time in Madrid: " + df.format(date));

如果您想要获取运行程序的计算机的本地时区,请使用:

df.setTimeZone(TimeZone.getDefault());

似乎有些困难:https://mkyong.com/java8/java-display-all-zoneid-and-its-utc-offset/ - mjs
@mmm 我所写的是,具体来说 java.util.Date 对象不包含时区信息。这并不意味着 Java 在一般情况下不知道时区 - 实际上,正如您发现的那样,它确实知道时区。您链接的示例只打印了 Java 知道的时区,这与 java.util.Date 类别无关。该示例根本没有使用这个类别。 - Jesper
我只是在说 TimeZone.getTimeZone("") 接受一个字符串,而且在链接之前没有证据表明你提供的传递的字符串是有效的,因为根据文档,Java df.setTimezone 不会导致错误。 - mjs

16

使用日历(Calendar)很简单:

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Europe/Madrid"));
Date currentDate = calendar.getTime();

2
“GMT-2”不会给出“始终为GMT-2”的时区,这将不包括夏令时吗? - Jon Skeet
11
请阅读 http://stackoverflow.com/faq 上的 Stack Overflow 常见问题解答: “没有问题太琐碎或太“新手”。哦,对了,问题应该与编程有关。” - dfa
16
常见问题解答是正确的。如果有人在谷歌上搜索任何编程问题,我们希望Stack Overflow成为最顶部的搜索结果(或者非常靠近它)。这意味着即使是最琐碎的问题,如果它在SO上不存在,也可以发布。 - Bill the Lizard
5
即使您为一个日历实例设置了时间区域,它也不会被getTime()方法考虑在内。根据其Javadoc文档:返回代表此日历的时间值(从纪元开始的毫秒偏移量)的日期对象。 - Danny Lo
@dfa 我已经尝试了你的代码,但仍然得到了服务器本地时区(IST)。 - Nitin Dhomse
显示剩余6条评论

15

使用内置于Java 8及更高版本中的java.time类:

public static void main(String[] args) {
        LocalDateTime localNow = LocalDateTime.now(TimeZone.getTimeZone("Europe/Madrid").toZoneId());
        System.out.println(localNow);
        // Prints current time of given zone without zone information : 2016-04-28T15:41:17.611
        ZonedDateTime zoneNow = ZonedDateTime.now(TimeZone.getTimeZone("Europe/Madrid").toZoneId());
        System.out.println(zoneNow);
        // Prints current time of given zone with zone information : 2016-04-28T15:41:17.627+02:00[Europe/Madrid]
    }

2

看下这个,可能会有所帮助。对我来说运行很好。代码也考虑了夏令时。

    TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
    Calendar cal = Calendar.getInstance();      
    // If needed in hours rather than milliseconds
    int LocalOffSethrs = (int) ((cal.getTimeZone().getRawOffset()) *(2.77777778 /10000000));        
    int ChinaOffSethrs = (int) ((tz.getRawOffset()) *(2.77777778 /10000000));       
    int dts = cal.getTimeZone().getDSTSavings();
    System.out.println("Local Time Zone : " + cal.getTimeZone().getDisplayName());
    System.out.println("Local Day Light Time Saving : " + dts);
    System.out.println("China Time : " + tz.getRawOffset());
    System.out.println("Local Offset Time from GMT: " + LocalOffSethrs);
    System.out.println("China Offset Time from GMT: " + ChinaOffSethrs);    
    // Adjust to GMT
    cal.add(Calendar.MILLISECOND,-(cal.getTimeZone().getRawOffset()));  
    // Adjust to Daylight Savings
    cal.add(Calendar.MILLISECOND, - cal.getTimeZone().getDSTSavings());
    // Adjust to Offset
    cal.add(Calendar.MILLISECOND, tz.getRawOffset());       
    Date dt = new Date(cal.getTimeInMillis());              
    System.out.println("After adjusting offset Acctual China Time :" + dt); 

很不错的例子,但是使用我的时区(EST)测试并没有返回正确的值。使用 RawOffset 工作并没有考虑 DST,所以最终我得到了比实际早1小时的结果。 - Cygnusx1
通过添加/减去时间持续时间来“转换”到另一个时区会导致很多问题。要转换到另一个时区,您应该为新时区创建一个新的日历对象,设置该日期,然后使用get(int)方法获取该时区的时间值。 - fishinear

2
你可以使用JodaTime来处理这个问题。Java.util.Date 在时区方面非常有限。

java.util.Date故意与TimeZone分离。对于简单的“在特定时区中是什么时间”的情况,java.util.*还不错...但我同意Joda Time通常是更好的API。 - Jon Skeet

2

java.time

java.util日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到现代日期时间 API*

此外,以下是从Joda-Time 的主页引用的通知:

请注意,从 Java SE 8 开始,用户被要求迁移到 java.time(JSR-310)- JDK 的核心部分,该部分取代了此项目。

使用现代日期时间 API java.time 的解决方案: 如果您只想获取日期和时间(而不是时区信息),可以使用 LocalDateTime.#now(ZoneId)

非参数化重载的 LocalDateTime.#now 方法返回使用JVM时区的当前日期时间。它相当于使用 LocalDateTime.now(ZoneId.systemDefault()) 方法。

演示:

import java.time.LocalDateTime;
import java.time.ZoneId;

public class Main {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Europe/Madrid"));
        System.out.println(now);
    }
}

一个示例运行的输出:

2021-07-25T15:54:31.574424

在线演示

如果您想获取带有时区信息的日期和时间,可以使用ZonedDateTime.#now(ZoneId)。它的非参数化变体的行为与上述描述相同。

演示:

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Europe/Madrid"));
        System.out.println(now);
    }
}

一个示例运行的输出:

2021-07-25T16:08:54.741773+02:00[Europe/Madrid]

在线演示

教程:日期时间了解更多现代日期时间API。


* 如果因为任何原因,你必须坚持使用Java 6或Java 7,你可以使用ThreeTen-Backport将大部分java.time功能移植到Java 6和7。如果你正在为一个Android项目工作,而你的Android API级别仍然不符合Java-8,请查看通过desugaring可用的Java 8+ APIs如何在Android项目中使用ThreeTenABP


1
你可以尝试使用ZonedDateTime.now()。它可以在java.time包中找到。
import java.time.ZonedDateTime;

public class Temp {
public static void main(String args[]) {
    System.out.println(ZonedDateTime.now(ZoneId.of("Europe/Madrid")));
}

}

输出(我在印度加尔各答):

2021-09-17T14:46:14.341+02:00[Europe/Madrid]

1

我无法使用日历让它工作。你必须使用DateFormat。

//Wednesday, July 20, 2011 3:54:44 PM PDT
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("PST"));
final String dateTimeString = df.format(new Date());

//Wednesday, July 20, 2011
df = DateFormat.getDateInstance(DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("PST"));
final String dateString = df.format(new Date());

//3:54:44 PM PDT
df = DateFormat.getTimeInstance(DateFormat.FULL);
df.setTimeZone(Timezone.getTimeZone("PST"));
final String timeString = df.format(new Date());

如果您需要将日期/时间作为字符串使用,则DateFormat是一个不错的方法。如果您需要将值作为数字使用,则使用Calendar。 - fishinear

0

将日期存储到变量中。

public static  String  getCurrentDate(){
    final ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
    String Temporal= DateTimeFormatter.ofPattern("yyyy-MM-dd").format(now);
    String today= LocalDate.now().format(DateTimeFormatter.ofPattern(Temporal));
    return today;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接