验收标准:不论时间数据按照哪个时区输入,存储为GMT/UTC+0时区同时刻的毫秒级整型时间戳,用户能够感知到的时间都按照工程时区来呈现和输出。
5 示例代码示例只为说明问题,不好勿喷。
1)Java8之前的解决方案 (1)转换工具类——DateTimeUtilpackage dateTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
public class DateTimeUtil
{
/**
* datetime format
*/
public static final String YMDHMS = "yyyy-MM-dd HH:mm:ss";
/**
* REGEX_DATETIME
*/
private static final String REGEX_DATETIME = "^((\\d{2}(([02468][048])|([13579][26]))[\\-]?"
+ "((((0?[13578])|(1[02]))[\\-]?((0?[1-9])|([1-2][0-9])|(3[01])))"
+ "|(((0?[469])|(11))[\\-]?((0?[1-9])|([1-2][0-9])|(30)))"
+ "|(0?2[\\-]?((0?[1-9])|([1-2][0-9])))))"
+ "|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-]?"
+ "((((0?[13578])|(1[02]))[\\-]?((0?[1-9])|([1-2][0-9])|(3[01])))"
+ "|(((0?[469])|(11))[\\-]?((0?[1-9])|([1-2][0-9])|(30)))"
+ "|(0?2[\\-]?((0?[1-9])|(1[0-9])|(2[0-8]))))))" + "\\s"
+ "(((0?[0-9])|(1[0-9])|(2[0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9]))))?$";
/**
* convertToUtcTimeStamp<br>
* 将关注对象所在地的时间"yyyy-MM-dd HH:mm:ss"转换为UTC+0的毫秒级整型时间戳
* 关注对象所在地时区最好与工程时区相同,
* 但如果关注对象所在范围跨时区,关注对象所在地时区与工程时区也可以不同,
* 但这样呈现的时间数据会与输入有差别,其含义是与关注对象持续时间同时刻的工程时区的时间。
* 时间处理原则:不论时间数据按照哪个时区输入,
* 存储为UTC+0时区同时刻的毫秒级整型时间戳,用户能够感知到的时间都按照工程时区来呈现。
* @param strDateTime 关注对象所在地的时间"yyyy-MM-dd HH:mm:ss"
* @param iTimeZoneInMilliSec 关注对象所在地时区偏移量(毫秒级整型时间戳)
* @param iDstInMilliSec 关注对象所在地夏令时偏移量(毫秒级整型时间戳)
* @return UTC+0的毫秒级整型时间戳
*/
public static long convertToUtcTimeStamp(String strDateTime,
long iTimeZoneInMilliSec,
long iDstInMilliSec)
{
if (StringUtils.isEmpty(strDateTime) || !strDateTime.matches(REGEX_DATETIME))
{
return 0L;
}
Date oTime = null;
try
{
oTime = parseToDate(strDateTime);
}
catch (Exception e)
{
e.getMessage();
}
long iTimeStamp = 0L;
if (null != oTime)
{
iTimeStamp = oTime.getTime();
}
Calendar oCalendar = Calendar.getInstance(); // 获取当前日历对象
long iServerTimeZoneOffset = oCalendar.get(Calendar.ZONE_OFFSET); // 获取当前时区偏移量
long iServerDSTOffset = oCalendar.getTimeZone().getDSTSavings(); // 获取当前夏令时偏移量
// 计算UTC+0的毫秒级整型时间戳
long iUtcTimeStamp = iTimeStamp + iServerTimeZoneOffset + iServerDSTOffset
- iTimeZoneInMilliSec - iDstInMilliSec;
return iUtcTimeStamp;
}
/**
* convertToPrjDateTime<br>
* 将UTC+0的毫秒级整型时间戳转换为工程时区的时间"yyyy-MM-dd HH:mm:ss"<br/>
* @param iUtcTimeStamp UTC+0的毫秒级整型时间戳
* @param iPrjTimeZoneInMilliSec 工程时区偏移量(毫秒级整型时间戳)
* @param iPrjDstInMilliSec 工程夏令时偏移量(毫秒级整型时间戳)
* @return 工程时区的时间"yyyy-MM-dd HH:mm:ss"
*/
public static String convertToPrjDateTime(long iUtcTimeStamp,
long iPrjTimeZoneInMilliSec,
long iPrjDstInMilliSec)
{
Calendar oCalendar = Calendar.getInstance(); // 获取当前日历对象
long iServerTimeZoneOffset = oCalendar.get(Calendar.ZONE_OFFSET); // 获取当前时区偏移量
long iServerDSTOffset = oCalendar.getTimeZone().getDSTSavings(); // 获取当前夏令时偏移量
// 计算工程时区的时间
String strPrjDateTime = "";
Date oPrjDateTime = new Date(iUtcTimeStamp - iServerTimeZoneOffset - iServerDSTOffset
+ iPrjTimeZoneInMilliSec + iPrjDstInMilliSec);
strPrjDateTime = dateFormat(YMDHMS, oPrjDateTime);
return strPrjDateTime;
}
/**
* parseToDate
* @param value TimeStamp / 年-月-日 时:分:秒
* @return Date
* @throws Exception
*/
private static Date parseToDate(String value) throws Exception
{
Date date = null;
try
{
Long dataValue = Long.valueOf(value);
date = new Date(dataValue);
}
catch (Exception e)
{
date = parseDate(value, YMDHMS);
}
return date;
}
/**
* parseDate
* @param strDate 年-月-日 时:分:秒
* @param strFormat yyyy-MM-dd HH:mm:ss
* @return Date
* @throws Exception
*/
private static Date parseDate(String strDate, String strFormat) throws Exception
{
if (StringUtils.isEmpty(strFormat))
{
strFormat = YMDHMS;
}
DateFormat sdf = new SimpleDateFormat(strFormat);
return sdf.parse(strDate);
}
/**
* dateFormat
* @param strFormat yyyy-MM-dd HH:mm:ss
* @param oDate Date
* @return 年-月-日 时:分:秒
*/
private static String dateFormat(String strFormat, Date oDate)
{
SimpleDateFormat sdf = new SimpleDateFormat(strFormat);
String strDate = sdf.format(oDate);
return strDate;
}
}
(2)转换Demo——DateTimeTest
package DateTimeTest;
public class DateTimeTest
{
publicstaticvoid main(String[] args)
{
new DateTimeTest();
}
public DateTimeTest()
{
testConvertDateTime();
}
/**
* 测试日期时间转换不应该受到系统时区的影响。
* 无论系统部署在哪个时区,都应该准确存储GMT时间戳,呈现工程时区下的年-月-日 时:分:秒
*/
privatevoid testConvertDateTime()
{
String strDateTime01 = "2015-07-04 20:30:00";
longiDateTime01 = DateTimeUtil.convertToUtcTimeStamp(strDateTime01, 28800000l, 0);
System.out.println(iDateTime01);
longiDateTime02 = 1436013000000L;
String strDateTime02 = DateTimeUtil.convertToPrjDateTime(iDateTime02, 28800000l, 0);
System.out.println(strDateTime02);
}
}
2)Java8之后的解决方案 (1)转换工具类——ZonedDateTimeUtilpackage dateTime;
import org.apache.commons.lang.StringUtils;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class ZonedDateTimeUtil {
public static enum EnumDateTimeFormatter {
YMDHMS("yyyy-MM-dd HH:mm:ss", 1),
YMD("yyyy-MM-dd", 2),
HMS("HH:mm:ss", 3);
String name = "";
int index = 0;
private EnumDateTimeFormatter(String name, int index) {
this.name = name;
this.index = index;
}
public String getInfo() {
return this.name;
}
}
public static enum EnumZone {
ZONE_0("+00:00", 0),
ZONE_EAST1("+01:00", 1),
ZONE_EAST2("+02:00", 2),
ZONE_EAST3("+03:00", 3),
ZONE_EAST4("+04:00", 4),
ZONE_EAST5("+05:00", 5),
ZONE_EAST6("+06:00", 6),
ZONE_EAST7("+07:00", 7),
ZONE_EAST8("+08:00", 8),
ZONE_EAST9("+09:00", 9),
ZONE_EAST10("+10:00", 10),
ZONE_EAST11("+11:00", 11),
ZONE_EAST12("+12:00", 12),
ZONE_EAST13("+13:00", 13),
ZONE_WEST1("-01:00", 101),
ZONE_WEST2("-02:00", 102),
ZONE_WEST3("-03:00", 103),
ZONE_WEST4("-04:00", 104),
ZONE_WEST5("-05:00", 105),
ZONE_WEST6("-06:00", 106),
ZONE_WEST7("-07:00", 107),
ZONE_WEST8("-08:00", 108),
ZONE_WEST9("-09:00", 109),
ZONE_WEST10("-10:00", 110),
ZONE_WEST11("-11:00", 111),
ZONE_WEST12("-12:00", 112);
String name = "";
int index = 0;
private EnumZone(String name, int index) {
this.name = name;
this.index = index;
}
public String getInfo() {
return this.name;
}
}
/**
* convertToUtcTimeStamp
* 将关注对象所在地的时间"yyyy-MM-dd HH:mm:ss"转换为UTC+0的毫秒级整型时间戳
* <p>
* 关注对象所在地时区最好与工程时区相同,
* 但如果关注对象所在范围跨时区,关注对象所在地时区与工程时区也可以不同,
* 但这样呈现的时间数据会与输入有差别,其含义是与关注对象持续时间同时刻的工程时区的时间。
* 时间处理原则:不论时间数据按照哪个时区输入,
* 存储为UTC+0时区同时刻的毫秒级整型时间戳,用户能够感知到的时间都按照工程时区来呈现和输出。
*
* @param strDateTime 关注对象所在地的时间"yyyy-MM-dd HH:mm:ss"
* @param enumDateTimeFormatter 时间格式
* @param enumZone 工程时区
* @return UTC+0的毫秒级整型时间戳
*/
public static long convertToUtcTimeStamp(String strDateTime,
EnumDateTimeFormatter enumDateTimeFormatter,
EnumZone enumZone) {
if (StringUtils.isEmpty(strDateTime)
|| null == enumDateTimeFormatter
|| null == enumZone) {
return 0L;
}
long iDateTime = ZonedDateTime.parse(
strDateTime,
DateTimeFormatter.ofPattern(enumDateTimeFormatter.getInfo()).withZone(ZoneId.of(enumZone.getInfo())))
.toInstant()
.toEpochMilli();
return iDateTime;
}
/**
* convertToPrjDateTime
* 将UTC+0的毫秒级整型时间戳转换为工程时区的时间"yyyy-MM-dd HH:mm:ss"
*
* @param iDateTime UTC+0的毫秒级整型时间戳
* @param enumDateTimeFormatter 时间格式
* @param enumZone 工程时区
* @return 工程时区的时间"yyyy-MM-dd HH:mm:ss"
*/
public static String convertToPrjDateTime(long iDateTime,
EnumDateTimeFormatter enumDateTimeFormatter,
EnumZone enumZone) {
if (null == enumDateTimeFormatter
|| null == enumZone) {
return "";
}
String strDateTime = LocalDateTime.ofInstant(
Instant.ofEpochMilli(iDateTime), ZoneId.of(enumZone.getInfo()))
.format(DateTimeFormatter.ofPattern(enumDateTimeFormatter.getInfo()));
return strDateTime;
}
}
(2)转换Demo——ZonedDateTimeTestpackage dateTime;
public class ZonedDateTimeTest {
public static void main(String[] args) {
new ZonedDateTimeTest();
}
public ZonedDateTimeTest() {
test();
}
private void test() {
String strDateTime01 = "2015-07-04 20:30:00";
long iDateTime02 = 1436013000000L;
// java8灏佽
long iDateTime = ZonedDateTimeUtil.convertToUtcTimeStamp(strDateTime01,
ZonedDateTimeUtil.EnumDateTimeFormatter.YMDHMS,
ZonedDateTimeUtil.EnumZone.ZONE_EAST8);
System.out.println(iDateTime);
String strDateTime = ZonedDateTimeUtil.convertToPrjDateTime(iDateTime02,
ZonedDateTimeUtil.EnumDateTimeFormatter.YMDHMS,
ZonedDateTimeUtil.EnumZone.ZONE_EAST8);
System.out.println(strDateTime);
String strDateTime1 = ZonedDateTimeUtil.convertToPrjDateTime(iDateTime02,
ZonedDateTimeUtil.EnumDateTimeFormatter.YMD,
ZonedDateTimeUtil.EnumZone.ZONE_EAST8);
System.out.println(strDateTime1);
String strDateTime2 = ZonedDateTimeUtil.convertToPrjDateTime(iDateTime02,
ZonedDateTimeUtil.EnumDateTimeFormatter.HMS,
ZonedDateTimeUtil.EnumZone.ZONE_EAST8);
System.out.println(strDateTime2);