Java:根据时区计算月份结束日期

时间:2018-08-02 01:09:32

标签: java calendar timezone

我有一种方法可以根据时区查找月份结束日期。

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
calendar.set(
    Calendar.DAY_OF_MONTH, 
    calendar.getActualMaximum(Calendar.DAY_OF_MONTH)
);
System.out.println(calendar.getTime());`

它显示输出:Thu Aug 30 18:04:54 PDT 2018

但是,它应该给我CET的输出。

我想念什么?

3 个答案:

答案 0 :(得分:4)

Calendar.getTime()方法返回一个Date对象,然后将其打印在代码中。问题是Date不包含任何时区概念,即使您已通过Calendar.getInstance()调用指定了时区。是的,的确令人困惑。

因此,要在特定时区中打印Date对象,必须使用SimpleDateFormat类,在打印前必须在其中调用SimpleDateFormat.setTimeZone()指定时区。

这是一个例子:

import java.util.Calendar;
import java.util.TimeZone;
import java.text.SimpleDateFormat;

public class TimeZoneTest {

    public static void main(String argv[]){
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CET"));
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        System.out.println("calendar.getTime(): " + calendar.getTime());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss z");
        sdf.setTimeZone(TimeZone.getTimeZone("CET"));
        System.out.println("sdf.format(): " + sdf.format(calendar.getTime()));
     }
}

这是我计算机上的输出:

calendar.getTime(): Fri Aug 31 01:40:17 UTC 2018
sdf.format(): 2018-Aug-31 03:40:17 CEST

答案 1 :(得分:1)

这是因为Date对象的状态没有时区,并且getTime()实际上返回一个与JVM时区相对应的日期,而您需要SimpleDateFormat进行格式化并在您所需的时区中打印日期。

如果尝试添加以下代码行,则可能会发现日历中的时区实际上是CET。

System.out.println(calendar.getTimeZone().getDisplayName()); 

答案 2 :(得分:1)

tl; dr

YearMonth                         // Represent a year-month without day-of-month.
.now(                             // Capture the current year-month as seen in the wall-clock time used by the people of a particular region (a time zone).
    ZoneId.of( "Africa/Tunis" )   // Specify your desired time zone. Never use 3-4 letter pseudo-zones such as `CET`. 
)                                 // Returns a `YearMonth` object.
.atEndOfMonth()                   // Determine the last day of this year-month. Returns a `LocalDate` object.
.atStartOfDay(                    // Let java.time determine the first moment of the day. Not necessarily 00:00:00, could be 01:00:00 or some other time-of-day because of anomalies such as Daylight Saving Time (DST). 
    ZoneId.of( "Africa/Tunis" )  
)                                 // Returns a `ZonedDateTime` object, representing a date, a time-of-day, and a time zone.

java.time

您使用的是可怕的旧Calendar类,该类早在几年前就被取代了,但是使用的是现代的 java.time 类。

LocalDate

如果仅需要日期,请使用LocalDate类。然后,时区与您的输出无关。

但是时区与确定当前日期非常相关。在任何给定时刻,日期都会在全球范围内变化。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如CETIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Europe/Paris" ) ;  // Or "Africa/Tunis" etc.
LocalDate today = LocalDate.now( z ) ;    // Capture the current date as seen by the wall-clock time used by the people of a certain region (a time zone).

YearMonth

获取该日期的月份。用YearMonth代表一年月。

YearMonth ym = YearMonth.from( today ) ;

或者跳过LocalDate

YearMonth ym = YearMonth.now( z ) ;

月底结束

LocalDate endOfThisMonth = ym.atEndOfMonth() ;

ISO 8601

要生成代表该String对象值的LocalDate,请调用toString。默认格式取自ISO 8601标准。对于将是YYYY-MM-DD的仅日期值,例如2018-01-23

String output = endOfThisMonth.toString() ;

如果需要其他格式,请使用DateTimeFormatter类。搜索堆栈溢出以获取许多示例和讨论。

时刻

如果需要一点时间,可以在LocalDate中添加时间和时区以获得ZonedDateTime。或者让ZonedDateTime确定一天中的第一时刻(并非总是00:00:00!)。

ZonedDateTime zdt = LocalDate.atStartOfDay( z ) ;

关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore