在Java中将日期转换为新时区
将Java在Java中将日期转换为新时区,java,date,timezone,simpledateformat,Java,Date,Timezone,Simpledateformat,将JavaDate对象转换为特定(“目标”)时区是一个在StackOverflow中多次提出的问题,建议的解决方案显然是: 通过时区偏移量调整日期对象的时间(毫秒)值 使用SimpleDataFormat(带时区)以字符串形式生成所需的日期 但是,似乎没有“普通Java”解决方案可以将日期字符串(带或不带时区)解析为日期对象,然后将相应的日历对象调整为目标时区,以便“转换”日期在所有情况下都以正确的方式运行(例如,当使用日历对象检索日期的年份时) 主要问题是,合理地说,当用于解析日期字符串的
Date
对象转换为特定(“目标”)时区是一个在StackOverflow
中多次提出的问题,建议的解决方案显然是:
- 通过时区偏移量调整
对象的时间(毫秒)值日期
- 使用
(带时区)以字符串形式生成所需的日期SimpleDataFormat
日期
对象,然后将相应的日历
对象调整为目标时区,以便“转换”日期在所有情况下都以正确的方式运行(例如,当使用日历
对象检索日期的年份时)
主要问题是,合理地说,当用于解析日期字符串的SimpleDataFormat
模式没有时区时,系统会假定时间在解析系统的时区中。但是,如果模式确实有时区,则时间从UTC
开始计算。因此,需要的是essentia一种关于原始日期字符串是否对应于有时区或无时区的模式的指示,显然,如果不分析模式本身,这是无法完成的
TimezoneDate
类附带的源代码演示了这些差异
以下是在太平洋标准时间(PST)上运行的机器上将main()
方法转换为UTC时,对2个“原始日期”(第一个没有时区,第二个有时区)运行的输出:
正确的操作是使两个示例日期字符串(“原始日期”)的“格式化”和“日历”字符串与“预期日期”相同
显然,我们需要区分日期字符串包含时区符号(TZ)和不包含时区符号(no TZ)的情况,但这意味着事先知道SimpleDataFormat
模式,这在处理date
对象而非原始字符串时是不可能的
因此,问题实际上是关于是否存在一个通用的“纯Java”(无第三方库)解决方案,该解决方案不需要事先了解模式,并且可以正确地使用相应的日历
对象
下面是TimezoneDate
类的完整源代码
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class TimezoneDate
{
private final Date time;
private final TimeZone timezone;
private final Calendar calendar;
/**
* Creates a wrapper for a {@code Date} object that is converted to the
* specified time zone.
*
* @param date The date to wrap
* @param timezone The timezone to convert to
*/
public TimezoneDate(Date date, TimeZone timezone)
{
this.calendar = TimezoneDate.getPlainCalendar(date, timezone);
this.time = this.calendar.getTime();
this.timezone = timezone;
}
private static Calendar getPlainCalendar(Date date, TimeZone timezone)
{
Calendar calendar = Calendar.getInstance(timezone);
calendar.setTime(date);
return calendar;
}
private static Calendar getAdjustedCalendar(Date date, TimeZone timezone)
{
long time = date.getTime();
time = time + timezone.getOffset(time) - TimeZone.getDefault().getOffset(time);
date = new Date(time);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar;
}
public int getYear()
{
return this.calendar.get(Calendar.YEAR);
}
public int getMonth()
{
return (this.calendar.get(Calendar.MONTH)+1);
}
public int getMonthDay()
{
return this.calendar.get(Calendar.DAY_OF_MONTH);
}
public int getHour()
{
return this.calendar.get(Calendar.HOUR_OF_DAY);
}
public int getMinutes()
{
return this.calendar.get(Calendar.MINUTE);
}
public int getSeconds()
{
return this.calendar.get(Calendar.SECOND);
}
public String toCalendarDate() // The date as reported by the Calendar
{
StringBuilder sb = new StringBuilder();
sb.append(this.getMonthDay()).append("/").append(this.getMonth()).
append("/").append(this.getYear()).append(" ").
append(this.getHour()).append(":").append(this.getMinutes()).
append(":").append(this.getSeconds());
return sb.toString();
}
public String toFormattedDate(boolean addTimezone) // The formatted date string
{
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
if (addTimezone)
{
sdf.setTimeZone(this.timezone);
}
return sdf.format(this.time);
}
public static void main(String[] args) throws Exception
{
// Each data "vector" contains 3 strings, i.e.:
// - Original (example) date
// - SimpleDateFormat pattern
// - Expected date after converting the original date to UTC
String[][] data = new String[][]
{
{"20/12/2012 08:12:24", "dd/MM/yyyy' 'HH:mm:ss", "20/12/2012 08:12:24"},
{"20/10/2012 08:12:24 +1200", "dd/MM/yyyy HH:mm:ss Z", "19/10/2012 20:12:24"}
};
Date originalDate;
TimezoneDate timezoneDate;
SimpleDateFormat format;
TimeZone UTC = TimeZone.getTimeZone("UTC");
for (String[] vector:data)
{
format = new SimpleDateFormat(vector[1]);
originalDate = format.parse(vector[0]);
timezoneDate = new TimezoneDate(originalDate, UTC);
System.out.println();
System.out.println("Original date: " + vector[0]);
System.out.println("Formatted date (TZ): " + timezoneDate.toFormattedDate(true));
System.out.println("Formatted date (no TZ): " + timezoneDate.toFormattedDate(false));
System.out.println("Calendar date: " + timezoneDate.toCalendarDate());
System.out.println("Expected date: " + vector[2]);
}
}
}
乔达时间
与其使用Java的
Date
,不如使用该类。这允许您以非常简单的方式执行时区操作,使用withTimezone()
和withTimezoneRetainFields()
方法取决于您的特定需求。当然,但所需的解决方案不应使用任何第三方库。只使用普通Java。我已经相应地澄清了这个问题。谢谢。虽然这是可以理解的,但日期和时间是基础Java支持非常不完善的一个方面。如果您可以等待Java 8,那么JSR-310是下一代Joda的核心。与此同时,您可以使用Joda或JSR-310参考实现,并在迁移到Java 8时执行相对较小的更改以使用核心库。在这种情况下,Java 8和JodaTime都不是一个选项。除了它是第三方库,它也不支持所有的DateFormat模式,这限制了它的可用性。@PNS我不理解您的注释DateTime格式。Joda Time有几十种内置的日期时间格式,内置对本地化格式的支持,您也可以定义自己的格式化程序。java.util.date/.Calendar以何种方式支持格式化superior还是缺少Joda Time?甚至Sun/Oracle也放弃了臭名昭著的麻烦的java.util.Date和.Calendar类。使用java 8中的任意一个或新的java.Time包。旧类在设计和实现上都有缺陷。
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class TimezoneDate
{
private final Date time;
private final TimeZone timezone;
private final Calendar calendar;
/**
* Creates a wrapper for a {@code Date} object that is converted to the
* specified time zone.
*
* @param date The date to wrap
* @param timezone The timezone to convert to
*/
public TimezoneDate(Date date, TimeZone timezone)
{
this.calendar = TimezoneDate.getPlainCalendar(date, timezone);
this.time = this.calendar.getTime();
this.timezone = timezone;
}
private static Calendar getPlainCalendar(Date date, TimeZone timezone)
{
Calendar calendar = Calendar.getInstance(timezone);
calendar.setTime(date);
return calendar;
}
private static Calendar getAdjustedCalendar(Date date, TimeZone timezone)
{
long time = date.getTime();
time = time + timezone.getOffset(time) - TimeZone.getDefault().getOffset(time);
date = new Date(time);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar;
}
public int getYear()
{
return this.calendar.get(Calendar.YEAR);
}
public int getMonth()
{
return (this.calendar.get(Calendar.MONTH)+1);
}
public int getMonthDay()
{
return this.calendar.get(Calendar.DAY_OF_MONTH);
}
public int getHour()
{
return this.calendar.get(Calendar.HOUR_OF_DAY);
}
public int getMinutes()
{
return this.calendar.get(Calendar.MINUTE);
}
public int getSeconds()
{
return this.calendar.get(Calendar.SECOND);
}
public String toCalendarDate() // The date as reported by the Calendar
{
StringBuilder sb = new StringBuilder();
sb.append(this.getMonthDay()).append("/").append(this.getMonth()).
append("/").append(this.getYear()).append(" ").
append(this.getHour()).append(":").append(this.getMinutes()).
append(":").append(this.getSeconds());
return sb.toString();
}
public String toFormattedDate(boolean addTimezone) // The formatted date string
{
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
if (addTimezone)
{
sdf.setTimeZone(this.timezone);
}
return sdf.format(this.time);
}
public static void main(String[] args) throws Exception
{
// Each data "vector" contains 3 strings, i.e.:
// - Original (example) date
// - SimpleDateFormat pattern
// - Expected date after converting the original date to UTC
String[][] data = new String[][]
{
{"20/12/2012 08:12:24", "dd/MM/yyyy' 'HH:mm:ss", "20/12/2012 08:12:24"},
{"20/10/2012 08:12:24 +1200", "dd/MM/yyyy HH:mm:ss Z", "19/10/2012 20:12:24"}
};
Date originalDate;
TimezoneDate timezoneDate;
SimpleDateFormat format;
TimeZone UTC = TimeZone.getTimeZone("UTC");
for (String[] vector:data)
{
format = new SimpleDateFormat(vector[1]);
originalDate = format.parse(vector[0]);
timezoneDate = new TimezoneDate(originalDate, UTC);
System.out.println();
System.out.println("Original date: " + vector[0]);
System.out.println("Formatted date (TZ): " + timezoneDate.toFormattedDate(true));
System.out.println("Formatted date (no TZ): " + timezoneDate.toFormattedDate(false));
System.out.println("Calendar date: " + timezoneDate.toCalendarDate());
System.out.println("Expected date: " + vector[2]);
}
}
}