Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中将日期转换为新时区_Java_Date_Timezone_Simpledateformat - Fatal编程技术网

在Java中将日期转换为新时区

在Java中将日期转换为新时区,java,date,timezone,simpledateformat,Java,Date,Timezone,Simpledateformat,将JavaDate对象转换为特定(“目标”)时区是一个在StackOverflow中多次提出的问题,建议的解决方案显然是: 通过时区偏移量调整日期对象的时间(毫秒)值 使用SimpleDataFormat(带时区)以字符串形式生成所需的日期 但是,似乎没有“普通Java”解决方案可以将日期字符串(带或不带时区)解析为日期对象,然后将相应的日历对象调整为目标时区,以便“转换”日期在所有情况下都以正确的方式运行(例如,当使用日历对象检索日期的年份时) 主要问题是,合理地说,当用于解析日期字符串的

将Java
Date
对象转换为特定(“目标”)时区是一个在
StackOverflow
中多次提出的问题,建议的解决方案显然是:

  • 通过时区偏移量调整
    日期
    对象的时间(毫秒)值
  • 使用
    SimpleDataFormat
    (带时区)以字符串形式生成所需的日期
但是,似乎没有“普通Java”解决方案可以将日期字符串(带或不带时区)解析为
日期
对象,然后将相应的
日历
对象调整为目标时区,以便“转换”日期在所有情况下都以正确的方式运行(例如,当使用
日历
对象检索日期的年份时)

主要问题是,合理地说,当用于解析日期字符串的
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]);
        }
    }
}