有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java中基于客户端/服务器偏移量显示本地时间的日历

我的客户端/浏览器在印度,我从javascript获得时区偏移 使用以下代码:

var now = new Date();
var localOffSet = now.getTimezoneOffset(); -330 // for India
int localOffSetMin = (localOffSet)*(-1); 

我的服务器位于纽约,因此我使用以下方法获取其偏移量:

 TimeZone timeZone = now.getTimeZone();
 int serverOffset = timeZone.getRawOffset();
 int serverOffSetMinutes = serverOffset / 60000; // -300 for America/New York

为了在我的机器上查找本地时间,我使用以下方法:

int offSets = Math.abs(serverOffSetMinutes-localOffSetMin); 

now.setTime(createDt); // createDt is date field value for some column
now.add(Calendar.MINUTE, offSets); // adds offset  
Date localDt = now.getTime(); 

但我得到的日期/时间比预期时间提前了1小时。我错过了什么


共 (2) 个答案

  1. # 1 楼答案

    一个java.util.Date对象has no timezone information。它只有一个long值,这是从1970-01-01T00:00:00Z开始的毫秒数(也称为“unix epoch”或仅“epoch”)。该值完全独立于时区(您也可以说“它在UTC中”)

    要将该值转换为另一个时区,不需要在时区之间进行所有这些计算。你只需要得到这个毫秒值,并将其转换为所需的时区

    要从javascript获取值,只需执行以下操作:

    var d = new Date();
    var millis = d.getTime();
    

    变量millis将包含从epoch开始的毫秒数。在我做的测试中,这个值是1499101493296

    要创建java.util.Date对象,只需执行以下操作:

    Date date = new Date(1499101493296L);
    

    要在您想要的时区中设置此日期的格式,请使用SimpleDateFormat

    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
    System.out.println(sdf.format(date));
    

    输出将是:

    03/07/2017 22:34:53

    如果需要不同的格式,请查看javadoc以了解更多信息

    还请注意,我使用了IANA format的时区名称(总是采用Continent/City格式,比如America/Sao_PauloEurope/Berlin)。 避免使用三个字母的缩写(如ISTEST),因为它们是ambiguous and not standard

    要使用另一个时区,可以使用IANA's names-使用^{检查所有可用的名称


    新的Java日期/时间API

    旧类(DateCalendarSimpleDateFormat)有lots of problemsdesign issues,它们正在被新的API所取代

    如果使用<强> java 8 < /St>,考虑使用^ {A8}。更容易些

    如果您使用的是Java<;=7,您可以使用ThreeTen Backport,这是Java 8新的日期/时间类的一个很好的后端口。对于Android,有ThreeTenABP(更多关于如何使用它here

    虽然您也可以使用Joda Time,但它处于维护模式,正在被新的API取代,因此我不建议使用它启动新项目。即使在joda's website中,它也说:“注意,Joda Time被认为是一个基本上“完成”的项目。没有计划进行重大的增强。如果使用Java SE 8,请迁移到Java.Time(JSR-310)。”

    下面的代码适用于这两种情况。 唯一的区别是包名(在Java 8中是^{),在ThreeTen Backport(或Android的ThreeTenABP)中是^{),但类和方法的名称是相同的

    一旦有了毫秒值,创建日期并转换为某个时区的代码非常相似:

    ZoneId zone = ZoneId.of("Asia/Kolkata");
    ZonedDateTime z = Instant.ofEpochMilli(1499101493296L).atZone(zone);
    System.out.println(z); // 2017-07-03T22:34:53.296+05:30[Asia/Kolkata]
    

    输出将是:

    2017-07-03T22:34:53.296+05:30[Asia/Kolkata]

    如果需要不同的格式,请使用DateTimeFormatter

    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss x");
    System.out.println(z.format(fmt)); // 03/07/2017 22:34:53 +0530
    

    输出将是:

    03/07/2017 22:34:53 +0530

    如果您想要不同的格式,请check the javadoc了解更多详细信息

    要使用另一个时区,可以使用IANA's names-使用^{检查所有可用的名称

  2. # 2 楼答案

    使用JavaSE进行日期和时间操作

    You can print a list of supported TimeZones by using the following code.

    System.out.println(TimeZone.getAvailableIDs().toString());
    

    然后,您可以使用以下代码查找并打印时区之间的差异。你必须记住夏令时

    public void printTimeZoneDifference(String from, String to) {
       TimeZone easternStandardTime = TimeZone.getTimeZone(from);
       TimeZone indiaStandardTime = TimeZone.getTimeZone(to);
    
       long milliseconds = easternStandardTime.getRawOffset() - indiaStandardTime.getRawOffset() + easternStandardTime.getDSTSavings() - indiaStandardTime.getDSTSavings();
       String difference = String.format("%02d min, %02d sec", TimeUnit.MILLISECONDS.toMinutes(milliseconds), TimeUnit.MILLISECONDS.toSeconds(milliseconds) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliseconds)));
    
       System.out.println("The difference in time between" + easternStandardTime.getDisplayName() + " and " + indiaStandardTime.getDisplayName() + " is " + difference);
     }
    

    虽然如果我要写这样的东西,我可能会传递一个时区对象作为参数,并让该方法单独负责减法。然后我要么打印结果,要么将其作为另一种方法的一部分。我没有这样组织帖子,因为我想在帖子中包含所有相关代码

    使用Joda操作日期和时间

    This type of manipulation has already been solved in Java. The Joda Time Library is probably your best bet if you are doing a lot of date manipulation. If you are only manipulating time in this one instance then it would be a bit over kill to include the dependency in your runtime.

    再次打印出时区

    public void printDateTimeZones() {
       for(String zone : DateTimeZone.getAvailableIDs()) {
          System.out.println(zone);
       }
    }
    

    然后,您可以使用以下代码的默认格式返回两个日期时区之间的句点(差)字符串

    public String printPeriod(String from, String to) {
       Period period = new Period(new DateTime(DateTimeZone.forID(to)), new DateTime(DateTimeZone.forID(from)));
       return PeriodFormat.getDefault().print(period);
    }
    

    类似地,Joda提供了一个format builder类,允许您指定首选格式

    public String printPeriod(String from, String to) {
       PeriodFormatter formatter = new PeriodFormatterBuilder()
         .printZeroRarelyFirst()
         .appendYears().appendSuffix(" Years").appendSeparator(",")
         .appendMonths().appendSuffix(" Months").appendSeparator(",")
         .appendWeeks().appendSuffix(" Weeks").appendSeparator(",")
         .appendDays().appendSuffix(" Days").appendSeparator(",")
         .appendHours().appendSuffix(" Hours").appendSeparator(",")
         .appendSeconds().appendSuffix(" Seconds").appendSeparator(",")
         .appendMillis().appendSuffix(" Milliseconds")
       .toFormatter();
    
       return formatter.print(new Period(new DateTime(DateTimeZone.forID(from)), new DateTime(DateTimeZone.forID(to))));
    }