Java日历和时间UTC到BST

时间:2017-01-21 09:48:54

标签: java datetime calendar java-8

我得到格式为yyyy-MM-dd HH:mm的字符串,表示UTC中的日期和时间。 下一步是将其放入日历(使用TimeZone UTC)。

此外,还需要创建一个单独的日历,将UTC转换为“欧洲/伦敦”时区(GMT / BST)。

之后我需要能够检测“欧洲/伦敦”日历是否有DST(日光节省偏移)。

下面的代码将向您显示我已经有多远,并且它在默认系统时区为GMT的英国计算机上运行正常。但是,当我在时区为UTC的PC上运行它时会失败。它似乎无法告诉我是否有DST_offset(它总是为零)。

      Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    cal.set(Calendar.YEAR, 2016);
    cal.set(Calendar.MONTH, 1);
    cal.set(Calendar.DAY_OF_MONTH, 27);
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 35);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    //This is required as Java Date JAN starts at 0.
    int MonthCon = cal.get(Calendar.MONTH)-1;
    cal.set(Calendar.MONTH, MonthCon);
    Date d = cal.getTime();



    SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");
    f.setTimeZone(TimeZone.getTimeZone("UTC"));
    System.out.println("UTC:    " + f.format(d));
    f.setTimeZone(TimeZone.getTimeZone("Europe/London"));
    System.out.println("BST:    " + f.format(d));

    //Creates a BST calendar of the same UTC time
    String dateStrBST = f.format(d);

    SimpleDateFormat curFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");
    curFormater.setTimeZone(TimeZone.getTimeZone("Europe/London"));
    Date dateObjBST = curFormater.parse(dateStrBST);


    System.out.println("BSTNewDate:    " + f.format(dateObjBST));


    Calendar calBST = Calendar.getInstance(TimeZone.getTimeZone("BST"));
    calBST.setTime(dateObjBST);

    System.out.println("Current TimeZone is : " +  calBST.getTimeZone());

    int offset = calBST.get(Calendar.DST_OFFSET);
    System.out.println("Day Light Savings: "+offset);
    System.out.println("Transition Day: "+isDSTTransitionDay(cal.get(Calendar.YEAR),cal.get(Calendar.MONTH),cal.get(Calendar.DAY_OF_MONTH))+"   Transition Type: "+DSTtransitionType(cal.get(Calendar.YEAR),cal.get(Calendar.MONTH),cal.get(Calendar.DAY_OF_MONTH)));

不幸的是,我需要能够检测到任何特定日期是否过渡日,也就是说从DST开启/关闭或关闭/开启的日期。同样,这适用于本地计算机,但不适用于UTC时区。

 private static boolean isDSTTransitionDay(int year, int month, int day) throws ParseException
 {
         Calendar calStartofDay = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
         calStartofDay.set(Calendar.YEAR, year);
         calStartofDay.set(Calendar.MONTH, month);
         calStartofDay.set(Calendar.DAY_OF_MONTH, day);
         calStartofDay.set(Calendar.HOUR_OF_DAY, 00);
         calStartofDay.set(Calendar.MINUTE, 0);
         calStartofDay.set(Calendar.SECOND, 1);            
         Date dStartofDay = calStartofDay.getTime();            

         SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");                        
         f.setTimeZone(TimeZone.getTimeZone("Europe/London"));            
         String dateStrUTCtoBST = f.format(dStartofDay);


         SimpleDateFormat curFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");
         curFormater.setTimeZone(TimeZone.getTimeZone("Europe/London"));
         Date dateObjBST = curFormater.parse(dateStrUTCtoBST);
         Calendar calBST = Calendar.getInstance();
         calBST.setTime(dateObjBST);            

         int offsetStart = calBST.get(Calendar.DST_OFFSET);

         calBST.add(Calendar.HOUR_OF_DAY, 23);

         int offsetEnd = calBST.get(Calendar.DST_OFFSET);
         //System.out.println("Start: "+offsetStart+" End: "+offsetEnd);




         if (offsetEnd == offsetStart) 
         {
             return false;
         }else
             {
                 //if(offsetStart<offsetEnd) {System.out.println("Transition to BST");}else{System.out.println("Transition to UTC/GMT");};
                 return true;
             }
 }

因此,在UTC计算机上它会失败,因为它始终将Calendar.DST_OFFSET置于零。我明显误解了一些事情,所以任何帮助/清晰度都会很好。

我几乎不得不保留Calendars,因为其他代码使用它但我意识到Java8有许多更奇特的方法来做事。

2 个答案:

答案 0 :(得分:2)

请允许我说实话,我试着阅读你的代码并且不太了解你试图获得你想要的东西的方式。如果您可以使用Java 8,我建议您切换到使用Java 8日期和时间类。有了这些,你的工作并不复杂。对于我去年10月30日选择的演示,即英国(和欧盟)从夏季时间(夏令时)变回标准时间的日期。

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
sudo apt-get install -y libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev

wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.43.tar.xz
tar xf bluez-5.43.tar.xz
cd bluez-5.43/

./configure
make
sudo make install
sudo reboot

# check version
bluetoothctl -v

sudo nano /lib/systemd/system/bluetooth.service
        # Add --experimental to this lane 
        ExecStart=/usr/local/libexec/bluetooth/bluetoothd --experimental

sudo systemctl daemon-reload
sudo systemctl restart bluetooth
sudo hciconfig hci0 up
sudo reboot

sudo usermod -G bluetooth -a pi
sudo reboot

答案 1 :(得分:0)

您正在使用

Calendar calBST = Calendar.getInstance();

将calBST设置为计算机的时区(在UTC计算机上,它将是UTC)。

calBST.setTime(dateObjBST);设置时间,而不是时区。

也可以尝试使用getInstance(TimeZone zone)

无论如何,我会像这样替换你的代码:

Calendar calStartofDay = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calStartofDay.set(Calendar.YEAR, 2017);
calStartofDay.set(Calendar.MONTH, 0);
calStartofDay.set(Calendar.DAY_OF_MONTH, 21);
calStartofDay.set(Calendar.HOUR_OF_DAY, 00);
calStartofDay.set(Calendar.MINUTE, 0);
calStartofDay.set(Calendar.SECOND, 1);            

Calendar calBST = Calendar.getInstance(TimeZone.getTimeZone("Europe/London"));
calBST.setTimeInMillis(calStartofDay.getTimeInMillis());
// use this to check the time
System.out.printf("%tc%n", calBST);

另外,从日历文档中,请注意:

  

set(f,value)将日历字段f更改为值。另外,它设定   内部成员变量,表示日历字段f已经过   改变。虽然日历字段f立即更改,但是   日历的时间值(以毫秒为单位)不会重新计算,直到下一个   调用get(),getTime(),getTimeInMillis(),add()或roll()。   因此,对set()的多次调用不会触发多次,不必要的   计算。使用set()更改日历字段的结果,   其他日历字段也可能会更改,具体取决于日历   字段,日历字段值和日历系统。此外,   get(f)不一定返回通过调用set设置的值   重新计算日历字段后的方法。具体细节   由具体日历类确定。