首页 文章

转换给定时区的日期/时间 - java

提问于
浏览
56

我想将这张GMT时间戳转换为格林威治标准时间13:

2011-10-06 03:35:05

我尝试过大约100种不同的DateFormat,TimeZone,Date,GregorianCalendar等组合来尝试做这个非常基本的任务 .

这段代码完成了我对CURRENT TIME的要求:

Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));

DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");    
formatter.setTimeZone(TimeZone.getTimeZone("GMT+13"));  

String newZealandTime = formatter.format(calendar.getTime());

但我想要的是设定时间而不是使用当前时间 .

我发现任何时候我都尝试设置这样的时间:

calendar.setTime(new Date(1317816735000L));

使用本地机器的TimeZone . 这是为什么?我知道当“new Date()”返回UTC 0时间时,为什么当你设置Time以毫秒为单位时,它不再假设时间是UTC?

有可能:

  • 设置对象的时间(日历/日期/时间标准)

  • (可能)设置初始时间戳的时区(calendar.setTimeZone(...))

  • 使用新的TimeZone格式化时间戳(formatter.setTimeZone(...)))

  • 返回具有新时区时间的字符串 . (formatter.format(calendar.getTime()))

在此先感谢您的帮助:D

14 回答

  • -1

    For me, the simplest way to do that is:

    Calendar calendar = Calendar.getInstance();
    calendar.setTime(new Date());
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    
    //Here you say to java the initial timezone. This is the secret
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    //Will print in UTC
    System.out.println(sdf.format(calendar.getTime()));    
    
    //Here you set to your timezone
    sdf.setTimeZone(TimeZone.getDefault());
    //Will print on your default Timezone
    System.out.println(sdf.format(calendar.getTime()));
    
  • 28

    了解计算机时间的工作原理非常重要 . 有了这个说我同意,如果创建一个API来帮助您像实时一样处理计算机时间,那么它应该以允许您像实时一样对待它的方式工作 . 在大多数情况下都是这种情况,但有一些重要的疏忽需要注意 .

    无论如何我离题!如果您有UTC偏移(最好在UTC中工作而不是GMT偏移),您可以计算时间(以毫秒为单位)并将其添加到时间戳中 . 请注意,SQL时间戳可能与Java时间戳不同,因为计算时间的过程并不总是相同的 - 这取决于数据库技术和操作系统 .

    我建议您使用System.currentTimeMillis()作为时间戳,因为这些可以在java中更一致地处理,而不必担心将SQL时间戳转换为Java Date对象等 .

    要计算您的偏移量,您可以尝试这样的事情:

    Long gmtTime =1317951113613L; // 2.32pm NZDT
    Long timezoneAlteredTime = 0L;
    
    if (offset != 0L) {
        int multiplier = (offset*60)*(60*1000);
        timezoneAlteredTime = gmtTime + multiplier;
    } else {
        timezoneAlteredTime = gmtTime;
    }
    
    Calendar calendar = new GregorianCalendar();
    calendar.setTimeInMillis(timezoneAlteredTime);
    
    DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
    
    formatter.setCalendar(calendar);
    formatter.setTimeZone(TimeZone.getTimeZone(timeZone));
    
    String newZealandTime = formatter.format(calendar.getTime());
    

    我希望这是有帮助的!

  • 0

    与往常一样,我建议您阅读有关Java日期和时间的this article,以便您了解它 .

    基本的想法是“在引擎盖下”,自纪元以来,一切都以UTC毫秒完成 . 这意味着如果您在不使用时区的情况下进行操作最简单,除了用户的字符串格式 .

    因此,我会跳过你建议的大部分步骤 .

    • 设置对象的时间(日期,日历等) .

    • 在格式化程序对象上设置时区 .

    • 从格式化程序返回一个字符串 .

    或者,您可以使用Joda time . 我听说它是一个更直观的日期时间API .

  • -1

    tl;博士

    如果输入 1317816735000L ...

    Instant.ofEpochMilli( 1_317_816_735_000L )     // Represent a moment in UTC using a count of milliseconds since the epoch reference of 1970-01-01T00:00Z.
    .atZone( ZoneId.of( "Pacific/Auckland" ) )     // Adjust from UTC into the wall-clock time used by the people of a certain region (a time zone). Returns a `ZonedDateTime` object.
    .format(                 
        DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM )
        .withLocale( new Locale( "en" , "NZ" ) )   // Locale specifies the human language and cultural norms used in localization.
    )                                              // Returns a `String` object that represents the value of our `ZonedDateTime` object’s value.
    

    如果输入 2011-10-06 03:35:05 ...

    LocalDateTime.parse(                  // Parse input string lacking any indicator of time zone or offset-from-UTC using the `LocalDateTime` class.
        "2011-10-06 03:35:05"
        .replace( " " , "T" )             // Comply with ISO 8601 standard by replacing SPACE in the middle with a `T`.
    )                                     // Returns a `LocalDateTime` object.
    .atZone(                              // Adjust from UTC into the wall-clock time used by the people of a certain region (a time zone). Returns a `ZonedDateTime` object.
        ZoneId.of( "Pacific/Auckland" )   // Always specify a time zone by `Continent/Region` name. Never use 3-4 pseudo-time-zones such as `PST`, `CST`, or `IST`.
    )                                     // Returns a `ZonedDateTime` object.
    

    java.time

    问题和大多数答案使用最早版本的Java过时的旧日期时间类 . 事实证明,这些旧课程很麻烦,令人困惑 . 避免他们 . 而是使用java.time类 .

    ISO 8601

    您的输入字符串几乎是标准ISO 8601格式 . 只需用 T 替换中间的SPACE即可 .

    String input = "2011-10-06 03:35:05".replace( " " , "T" ) ;  // Comply with ISO 8601 standard format by replacing the SPACE with a `T`.
    

    在解析/生成字符串时,java.time类默认使用这些标准格式 . 因此无需指定格式化模式 .

    LocalDateTime

    现在解析为LocalDateTime因为输入缺少有关UTC或时区偏移的任何信息 . LocalDateTime 没有偏移或时区的概念,因此它不代表时间轴上的实际时刻 .

    LocalDateTime ldt = LocalDateTime.parse( input );
    

    ZoneOffset

    您似乎在说,从业务环境中您知道此字符串的意图是表示比UTC早13个小时的时刻 . 所以我们实例化一个ZoneOffset .

    ZoneOffset offset = ZoneOffset.ofHours( 13 ); // 13 hours ahead of UTC, in the far east of the globe.
    

    OffsetDateTime

    应用它来获取OffsetDateTime对象 . 这成为时间轴上的实际时刻 .

    OffsetDateTime odt = ldt.atOffset( offset);
    

    ZoneId

    但是你提到了新西兰 . 所以你有一个特定的时区 . 时区是与UTC的偏移量加上一组用于处理诸如夏令时(DST)等异常的规则 . 所以我们可以指定 ZoneIdZonedDateTime 而不是仅仅偏移 .

    指定proper time zone name . 切勿使用3-4字母缩写,如 ESTIST ,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!) . 例如, Pacific/Auckland .

    ZoneId z = ZoneId.of( "Pacific/Auckland" );
    

    ZonedDateTime

    应用 ZoneId .

    ZonedDateTime zdt = ldt.atZone( z );
    

    您可以轻松调整到另一个区域时间轴上的时刻 .

    ZoneId zParis = ZoneId.of( "Europe/Paris" );
    ZonedDateTime zdtParis = zdt.withZoneSameInstant( zParis );  // Same moment in time, but seen through lens of Paris wall-clock time.
    

    从时代算起

    我强烈建议不要将日期时间值作为纪元的计数处理,例如从UTC 1970年开始的毫秒数 . 但如果必须,请从这样的数字创建一个 Instant .

    Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L );
    

    然后根据需要分配如上所示的时区,以远离UTC .

    ZoneId z = ZoneId.of( "Pacific/Auckland" );
    ZonedDateTime zdt = instant.atZone( z );
    

    您的 1_317_816_735_000L 的值是:

    • 2011-10-05T12:12:15Z (2011年10月5日星期三12:12:15 GMT)

    • 2011-10-06T01:12:15+13:00[Pacific/Auckland] (2011年10月6日星期四01:12:15在新西兰奥克兰举行) .

    生成字符串

    要以标准ISO 8601格式生成字符串,只需调用 toString . 请注意 ZonedDateTime 明智地通过在方括号中附加时区名称来扩展标准格式 .

    String output = zdt.toString();
    

    对于其他格式,请搜索DateTimeFormatter类的Stack Overflow . 已经多次覆盖 .

    指定FormatStyleLocale .

    Locale l = new Locale( "en" , "NZ" );
    DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( l );
    String output = zdt.format( f );
    

    关于java.time

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

    Joda-Time项目现在位于maintenance 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 .

  • 1

    看一下,我不认为Java中的时区是GMT 13.所以我认为你必须使用:

    Calendar calendar = Calendar.getInstance();
    //OR Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    
    calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY)+13);
    
    Date d = calendar.getTime();
    

    (如果有更改“GMT”到该时区并删除第二行代码)

    要么

    SimpleDateFormat df = new SimpleDateFormat();
    df.setTimeZone(TimeZone.getTimeZone("GMT+13"));
    System.out.println(df.format(c.getTime()));
    

    如果您想设置特定的时间/日期,您还可以使用:

    calendar.set(Calendar.DATE, 15);
    calendar.set(Calendar.MONTH, 3);
    calendar.set(Calendar.YEAR, 2011);
    calendar.set(Calendar.HOUR_OF_DAY, 13); 
    calendar.set(Calendar.MINUTE, 45);
    calendar.set(Calendar.SECOND, 00);
    
  • 34

    解决方案实际上非常简单(纯粹,简单的Java):

    System.out.println(" NZ Local Time: 2011-10-06 03:35:05");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    LocalDateTime localNZ = LocalDateTime.parse("2011-10-06 03:35:05",formatter);
    ZonedDateTime zonedNZ = ZonedDateTime.of(localNZ,ZoneId.of("+13:00"));
    LocalDateTime localUTC = zonedNZ.withZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime();
    System.out.println("UTC Local Time: "+localUTC.format(formatter));
    

    输出是:

    NZ Local Time: 2011-10-06 03:35:05
    UTC Local Time: 2011-10-05 14:35:05
    
  • 4

    Joda-Time

    java.util.Date/Calendar类是一团糟,应该避免 .

    更新:Joda-Time项目处于维护模式 . 该团队建议迁移到java.time类 .

    以下是使用Joda-Time 2.3库的答案 . 很容易 .

    如示例代码中所述,我建议您尽可能使用命名时区,以便您的编程可以处理Daylight Saving Time(DST)和其他异常 .

    如果你在字符串的中间放置了 T 而不是空格,你可以跳过前两行代码,处理格式化程序来解析字符串 . DateTime构造函数可以采用ISO 8601格式的字符串 .

    // © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
    // import org.joda.time.*;
    // import org.joda.time.format.*;
    
    // Parse string as a date-time in UTC (no time zone offset).
    DateTimeFormatter formatter = org.joda.time.format.DateTimeFormat.forPattern( "yyyy-MM-dd' 'HH:mm:ss" );
    DateTime dateTimeInUTC = formatter.withZoneUTC().parseDateTime( "2011-10-06 03:35:05" );
    
    // Adjust for 13 hour offset from UTC/GMT.
    DateTimeZone offsetThirteen = DateTimeZone.forOffsetHours( 13 );
    DateTime thirteenDateTime = dateTimeInUTC.toDateTime( offsetThirteen );
    
    // Hard-coded offsets should be avoided. Better to use a desired time zone for handling Daylight Saving Time (DST) and other anomalies.
    // Time Zone list… http://joda-time.sourceforge.net/timezones.html
    DateTimeZone timeZoneTongatapu = DateTimeZone.forID( "Pacific/Tongatapu" );
    DateTime tongatapuDateTime = dateTimeInUTC.toDateTime( timeZoneTongatapu );
    

    转储这些 Value ......

    System.out.println( "dateTimeInUTC: " + dateTimeInUTC );
    System.out.println( "thirteenDateTime: " + thirteenDateTime );
    System.out.println( "tongatapuDateTime: " + tongatapuDateTime );
    

    跑的时候......

    dateTimeInUTC: 2011-10-06T03:35:05.000Z
    thirteenDateTime: 2011-10-06T16:35:05.000+13:00
    tongatapuDateTime: 2011-10-06T16:35:05.000+13:00
    
  • 0

    我试过这段代码

    try{
                SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss Z");
                Date datetime = new Date();
    
                System.out.println("date "+sdf.format(datetime));
    
                sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
    
                System.out.println("GMT "+ sdf.format(datetime));
    
                sdf.setTimeZone(TimeZone.getTimeZone("GMT+13"));
    
                System.out.println("GMT+13 "+ sdf.format(datetime));
    
                sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    
                System.out.println("utc "+sdf.format(datetime));
    
                Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
    
                DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");    
                formatter.setTimeZone(TimeZone.getTimeZone("GMT+13"));  
    
                String newZealandTime = formatter.format(calendar.getTime());
    
                System.out.println("using calendar "+newZealandTime);
    
            }catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    

    得到这个结果

    date 06-10-2011 10:40:05 +0530
    GMT 06-10-2011 05:10:05 +0000 // here getting 5:10:05
    GMT+13 06-10-2011 06:10:05 +1300 // here getting 6:10:05
    utc 06-10-2011 05:10:05 +0000
    using calendar 06 Oct 2011 18:10:05 GMT+13:00
    
  • 21

    我们可以使用偏移值来处理这个问题

    public static long convertDateTimeZone(long lngDate, String fromTimeZone,
            String toTimeZone){
        TimeZone toTZ = TimeZone.getTimeZone(toTimeZone);
        Calendar toCal = Calendar.getInstance(toTZ);        
    
        TimeZone fromTZ = TimeZone.getTimeZone(fromTimeZone);
        Calendar fromCal = Calendar.getInstance(fromTZ);
        fromCal.setTimeInMillis(lngDate);
        toCal.setTimeInMillis(fromCal.getTimeInMillis()
                + toTZ.getOffset(fromCal.getTimeInMillis())
                - TimeZone.getDefault().getOffset(fromCal.getTimeInMillis()));      
        return toCal.getTimeInMillis();
    }
    

    测试代码段:

    System.out.println(new Date().getTime())
     System.out.println(convertDateTimeZone(new Date().getTime(), TimeZone
                    .getDefault().getID(), "EST"));
    

    输出:1387353270742 1387335270742

  • 10

    我们可以从给定日期获得UTC / GMT时间戳 .

    /**
     * Get the time stamp in GMT/UTC by passing the valid time (dd-MM-yyyy HH:mm:ss)
     */
    public static long getGMTTimeStampFromDate(String datetime) {
        long timeStamp = 0;
        Date localTime = new Date();
    
        String format = "dd-MM-yyyy HH:mm:ss";
        SimpleDateFormat sdfLocalFormat = new SimpleDateFormat(format);
        sdfLocalFormat.setTimeZone(TimeZone.getDefault());
    
        try {
    
            localTime = (Date) sdfLocalFormat.parse(datetime); 
    
            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"),
                    Locale.getDefault());
            TimeZone tz = cal.getTimeZone();
    
            cal.setTime(localTime);
    
            timeStamp = (localTime.getTime()/1000);
            Log.d("GMT TimeStamp: ", " Date TimegmtTime: " + datetime
                    + ", GMT TimeStamp : " + localTime.getTime());
    
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
        return timeStamp;
    
    }
    

    它将根据传递的日期返回UTC时间 .

    • 我们可以像UTC时间戳一样反向到当前日期和时间(反之亦然)
    public static String getLocalTimeFromGMT(long gmtTimeStamp) {
                 try{
                        Calendar calendar = Calendar.getInstance();
                        TimeZone tz = TimeZone.getDefault();
                        calendar.setTimeInMillis(gmtTimeStamp * 1000);
        //              calendar.add(Calendar.MILLISECOND, tz.getOffset(calendar.getTimeInMillis())); 
                        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
                        Date currenTimeZone = (Date) calendar.getTime();
                        return sdf.format(currenTimeZone);
                    }catch (Exception e) {
                    }
                    return "";  
                }
    

    我希望这会有助于其他人 . 谢谢!!

  • 2

    A quick way is :

    String dateText ="Thu, 02 Jul 2015 21:51:46";
    long hours = -5; // time difference between places
    
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(E, dd MMM yyyy HH:mm:ss, Locale.ENGLISH);     
    LocalDateTime date = LocalDateTime.parse(dateText, formatter);        
    date = date.with(date.plusHours(hours));
    
    System.out.println("NEW DATE: "+date);
    

    产量

    NEW DATE: 2015-07-02T16:51:46

  • 1
    public Timestamp convertLocalTimeToServerDatetime(String dt,String timezone){
    
        String clientDnT = dt ;// "2017-06-01 07:20:00";
        try{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(clientDnT);
        TimeZone tz = TimeZone.getTimeZone(timezone.trim()); // get time zone of user
        sdf.setTimeZone(tz);
    
        // Convert to servertime zone 
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        TimeZone tzInAmerica = TimeZone.getDefault();
        sdf1.setTimeZone(tzInAmerica);
    
        // assign date to date
        String serverDate = sdf1.format(date);
    
        // Convert to servertime zone to Timestamp
        Date date2 =  sdf.parse(serverDate);
        Timestamp tsm = new Timestamp(date2.getTime());
        return  tsm;
        }
        catch(Exception e){
            System.err.println(e);
        }
    
        return null;
    }
    
  • 0

    一些简单的方法 . 一个重要的事情要记住,Date不会维护时区,它只是 long millis 数字,因为它在这里处理 .

    /**
     * Converts source in GMT+0 to timezone specified by server
     * 
     * @throws IllegalStateException if server timezone wasnt set
     */
    public static Date convertGmt(Date source)
    {
        if (timeZoneServer == null)
        {
            throw new IllegalStateException("Server timezone wasnt set");
        }
    
        long rawOffset = timeZoneServer.getRawOffset();
    
        Date dest = new Date(source.getTime() + rawOffset);
    
        return dest;
    }
    
    /**
     * Converts source in device timezone format to GMT
     */
    public static Date convertToGmt(Date source)
    {
        int rawOffset = TimeZone.getDefault().getRawOffset();
    
        Date dest = new Date(source.getTime() - rawOffset);
    
        return dest;
    }
    

    TimezoneServer就像 TimeZone timeZoneServer = TimeZone.getTimeZone("GMT+1")

  • 4

    您的方法无需任何修改即可运行

    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    // Timestamp for 2011-10-06 03:35:05 GMT
    calendar.setTime(new Date(1317872105000L));
    
    DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); 
    formatter.setTimeZone(TimeZone.getTimeZone("GMT+13"));
    
    // Prints 2011-10-06 16:35:05 GMT+13:00
    System.out.println(formatter.format(calendar.getTime()));
    

相关问题