我从前端传递日期,即IST(印度时区的日期)。在java代码中,我使用以下代码将日期转换为日历(这发生在美国PST时区的服务器中)。
Calendar cal = Calendar.getInstance();
int offset = date.getTimezoneOffset();
logger.info("Calendar Instance - " + cal);
cal.setTime(date);
logger.info("Calendar Instance after setting date - " + cal);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
logger.info("Calendar Instance after setting zeros - " + cal);
return cal;
所以当我看到最后一个日志时,那个月的日子会比我传递的日子少一天。如果我通过22/06/2015 IST,它将转移到2015年6月21日。所以在处理完毕后,它会在另一个UI页面的数据列表中显示21/06/2015。
答案 0 :(得分:5)
这是因为服务器端的JVM和客户端的JVM默认使用不同的时区Java TimeZone:
通常,您使用getDefault获取TimeZone,这会创建一个 TimeZone基于程序运行的时区。对于 例如,对于在日本运行的程序,getDefault会创建一个TimeZone 基于日本标准时间的对象。
我们可以看到,服务器上的Pacific Time Zone UTC-8:00 ,客户端上的Indian Standard Time UTC + 05:30 。它们相差 13.30 ,印度日期X转换为美国为X-13.30,可能会在服务器端为某些X产生前一天。
根据您如何影响/修改服务器和客户端应用程序,可能会有一些变通方法。例如,您可以在服务器端和客户端使用UTC + 00:00时区中的日期。如果您需要向用户显示日期,您可以在需要时将其转换为印度时区。
// Set default GMT+0:00 time zone
TimeZone timeZone;
timeZone = TimeZone.getTimeZone("GMT+0:00");
TimeZone.setDefault(timeZone);
您可以创建"清除"而不是简单地使用Calendar cal = Calendar.getInstance();
。您稍后将用户设置日历,月份和年份的日历
public static Calendar createClearedCalendar() {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(timeZone);
cal.set(1970, 0, 1, 0, 0, 0);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.clear(Calendar.MILLISECOND);
return cal;
}
顺便说一下,如果你在Java中操纵日期时间,你可以考虑Joda Time,它有更多扩展选项和optimized performance。
答案 1 :(得分:0)
The Answer是正确的,应该被接受(点击大空的复选标记)。
本回答添加了一些想法和示例代码。
避免使用或甚至考虑这些3或4个字母代码,例如IST
或PST
。它们不是标准化的,它们不是唯一的,它们进一步混淆了Daylight Saving Time (DST)周围的问题。例如,IST表示“印度标准时间”,“爱尔兰标准时间”等等。
使用proper time zone names。其中大多数都处于“大陆”+“/”+“城市/地区”模式。城市/地区名称并非专门针对该城镇,而是作为一个易于识别的名称,尽可能广泛的区域,共享time zone rules和异常的过去,现在和未来规则(包括DST)。
通常,您应该使用UTC time zone进行所有业务逻辑,数据存储和数据交换。仅在用户需要时进行演示时调整到特定时区。
旧的java.util.Date/.Calendar类是处理日期时间工作的大胆尝试,但最终它们失败了。众所周知,它们在设计和实施方面都很麻烦。避免他们。
第三方Joda-Time库是一种解决方案。它适用于许多Java版本以及Android版本。 Joda-Time启发了另一个解决方案,即Java 8及更高版本(java.time package)中的Tutorial。
该问题似乎的目标是获取java.util.Date对象,分配所需的时区,并生成java.util.Calendar对象。
幸运的是,java.time框架具有转换方法。请参阅this Tutorial page。
示例代码如下,使用Java 8 Update 45中的java.time。
您可能需要导入,例如:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
让我们模拟传入java.util.Date。我们将基于“now”实例化一个Date。
Date inputDate = new Date( ); // Simulate getting a java.util.Date object.
然后我们使用proper time zone names定义所需的时区。让我们一起玩蒙特利尔,以及问题中提到的太平洋美国和印度时区。
ZoneId zoneLosAngeles = ZoneId.of( "America/Los_Angeles" );
ZoneId zoneMontréal = ZoneId.of( "America/Montreal" );
ZoneId zoneKolkata = ZoneId.of( "Asia/Kolkata" );
然后我们将其转换为Instant
,即时间轴上的一个点,而不考虑时区。
Instant instant = inputDate.toInstant( );
然后我们分配各种时区来创建ZonedDateTime
个实例。了解我们如何以两种方式实例化ZonedDateTime:[a]来自Instant,或[b]来自另一个ZonedDateTime来自withZoneSameInstant
方法。两种方式如下所示。
请注意,java.time(和Joda-Time)使用immutable objects,这是一种设计模式,我们根据旧实例创建新实例,而不是改变(“改变”)旧实例。 Thread-safety是主要的好处之一。
ZonedDateTime zdtLosAngeles = ZonedDateTime.ofInstant( instant, zoneLosAngeles );
ZonedDateTime zdtMontréal = ZonedDateTime.ofInstant( instant, zoneMontréal );
ZonedDateTime zdtKolkata = ZonedDateTime.ofInstant( instant, zoneKolkata );
ZonedDateTime zdtUtc = zdtKolkata.withZoneSameInstant( ZoneOffset.UTC );
最后,我们将其中一个转换为GregorianCalendar
对象,该对象是java.util.Calendar
的子类。
GregorianCalendar calendarKolkata = GregorianCalendar.from( zdtKolkata );
转储到控制台。
System.out.println( "inputDate: " + inputDate );
System.out.println( "zdtLosAngeles: " + zdtLosAngeles );
System.out.println( "zdtMontréal: " + zdtMontréal );
System.out.println( "zdtKolkata: " + zdtKolkata );
System.out.println( "zdtUtc: " + zdtUtc );
System.out.println( "calendarKolkata: " + calendarKolkata );
跑步时。
inputDate: Wed Jun 24 15:12:12 PDT 2015
zdtLosAngeles: 2015-06-24T15:12:12.153-07:00[America/Los_Angeles]
zdtMontréal: 2015-06-24T18:12:12.153-04:00[America/Montreal]
zdtKolkata: 2015-06-25T03:42:12.153+05:30[Asia/Kolkata]
zdtUtc: 2015-06-24T22:12:12.153Z
calendarKolkata: java.util.GregorianCalendar[time=1435183932153,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Kolkata",offset=19800000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2015,MONTH=5,WEEK_OF_YEAR=26,WEEK_OF_MONTH=4,DAY_OF_MONTH=25,DAY_OF_YEAR=176,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=4,AM_PM=0,HOUR=3,HOUR_OF_DAY=3,MINUTE=42,SECOND=12,MILLISECOND=153,ZONE_OFFSET=19800000,DST_OFFSET=0]