如何将本地时区转换为 utc 和 utc 本地时区?
How do I convert local time zone to utc and utc local time zone?
我想在数据库中存储 UTC 时间(yyyy-mm-dd
或 dd-mm-yyyy
)
- 我想将本地时区转换为 UTC 并将其存储在数据库中
我尝试了不同的方法,但都不能正常工作。下面是我将本地转换为 UTC
的代码
- 从 DB 获取 UTC 时间并转换为本地时区
下面是我的代码:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class TestDate {
public static void main(String[] args) {
/*Date de = new Date();
DateFormat converter1 = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
System.err.println(converter1.format(de));
Date der =*/
localToGMT();
// System.err.println("0000 : "+converter1.format(der));
Date d= new Date("09/10/2017 21:53:17");
gmttoLocalDate(d);
}
public static Date localToGMT() {
// Date gmt = new Date(sdf.format(date));
Date gmt = null;
Date localTime = new Date();
//creating DateFormat for converting time from local timezone to GMT
DateFormat converter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
//getting GMT timezone, you can get any timezone e.g. UTC
converter.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("local time : " + localTime);;
System.out.println("time in GMT : " + converter.format(localTime));
try {
gmt =converter.parse((converter.format(localTime)));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*Date date = new Date("2017/10/10 12:04:28");
System.err.println(date);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
gmt = sdf.parse(sdf.format(date));*/
System.err.println("converted to utc :" + gmt);
return gmt;
}
public static Date gmttoLocalDate(Date date) {
String timeZone = Calendar.getInstance().getTimeZone().getID();
Date local = new Date(date.getTime() + TimeZone.getTimeZone(timeZone).getOffset(date.getTime()));
System.err.println("converted to local timezone :" + local);
return local;
}
}
UTC 本地
public static Date localToUTC() {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date gmt = new Date(sdf.format(date));
return gmt;
}
UTC 到本地
public static Date utctoLocalDate(Date date) {
String timeZone = Calendar.getInstance().getTimeZone().getID();
Date local = new Date(date.getTime() + TimeZone.getTimeZone(timeZone).getOffset(date.getTime()));
return local
}
一个java.util.Date
has no timezone information。它只有一个 long
值,这是自 unix 纪元(即 1970-01-01T00:00:00Z
或 January 1st 1970 午夜以来的毫秒数在 UTC)。
这个值(自纪元以来的毫秒数)有,我简称为timestamp。
时间戳是一个“绝对”值,全世界都一样。
例子:我刚得到当前时间(System.currentTimeMillis()
),结果是1507722750315
(这是自纪元以来的当前毫秒数)。这个价值对世界上的每个人都是一样的。但是这个相同的值可以对应每个时区的不同date/time:
- 在UTC中对应
2017-10-11T11:52:30.315Z
- 在圣保罗(巴西),
2017-10-11T08:52:30.315-03:00
- 在伦敦,是
2017-10-11T12:52:30.315+01:00
- 在东京,
2017-10-11T20:52:30.315+09:00
- 在印度,是
2017-10-11T17:22:30.315+05:30
- 在奥克兰,
2017-10-12T00:52:30.315+13:00
(那里已经“明天”了)
- 等等...
因此,当您执行接收 java.util.Date
并尝试将其转换为另一个 java.util.Date
的方法时,您没有转换任何东西。 Date
仅包含时间戳值(对应于特定时间点的“绝对”值)。但是Date
本身对时区一无所知,所以做这样的转换是没有意义的(全世界的时间戳都是一样的,不需要转换)。
“但是当我打印日期时,我看到的是本地时间的值”
嗯,这个就解释好了in this article。如果你 System.out.println
一个 Date
,或者记录它,或者在调试器中查看它的值,你会看到类似的东西:
Wed Oct 12 12:33:99 IST 2017
但那是因为隐式调用了 toString()
方法,并且此方法将时间戳值转换为 JVM 默认时区(因此它看起来像“本地 date/time”)。
但是请记住,这个 Wed Oct etc
字符串 而不是 Date
对象持有的实际值:它所拥有的只是对应于该对象的时间戳date/time 显示。但是日期对象本身没有任何本地 date/time 的概念,也没有任何时区相关信息。您看到的只是时间戳值的表示,以特定格式,针对特定时区。
那怎么办?
如果数据库字段是date类型,那么JDBC驱动一般会处理,所以直接保存Date
对象即可。无需关心格式和时区,因为 Date
没有格式,也没有任何时区信息。
日期类型的问题在于任何 language/database/vendor/application 都以不同的方式显示它。 Java 的 Date.toString()
将其转换为 JVM 默认时区,一些数据库以特定格式显示(dd/mm/yyyy,或 yyyy-mm-dd 等)并转换为在中配置的任何时区数据库等。
但请记住,日期本身没有格式。它只有一个值,问题是相同的日期可以 表示 不同的格式。示例:2017 年 10 月 15 日 可以表示为 2017-10-15
、10/15/2017
、15th Oct 2017
、15 de Outubro de 2017
(在 pt_BR(葡萄牙语)语言环境)等等。格式(表示)不同,但Date
值相同
所以,如果你正在处理 Date
对象,数据库字段是与日期相关的类型,它 returns 并保存 Date
对象,只需使用它直接。
如果你想显示这个日期,但是,(显示给用户,或记录它),或者如果数据库字段是String
(或varchar,或任何其他与文本相关的类型),那就完全不同了。
打印日期(或将其转换为 String
)时,您可以使用 SimpleDateFormat
:
选择要转换的格式和时区
// a java.util.Date with the same timestamp above (1507722750315)
Date date = new Date(1507722750315L);
// choose a format
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// choose a timezone to convert to
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
// convert to a String
String formattedDate = sdf.format(date);
System.out.println(formattedDate); // 2017-10-11 17:22:30
在这种情况下,输出是:
2017-10-11 17:22:30
如果我将时区更改为另一个时区,结果将转换为:
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
// convert to a String
String formattedDate = sdf.format(date);
System.out.println(formattedDate); // 2017-10-11 12:52:30
现在的结果是:
2017-10-11 12:52:30
但是 Date
值仍然相同:如果您调用 date.getTime()
,它将 return 时间戳值,它仍然是 1507722750315
。我刚刚更改了这个日期的表示(格式和时区)。但是 Date
本身的值没有改变。
另请注意,我使用了 IANA timezones names(始终采用 Region/City
格式,例如 Asia/Kolkata
或 Europe/Berlin
)。
避免使用 3 个字母的缩写(如 IST
或 CET
),因为它们是 ambiguous and not standard.
您可以通过调用 TimeZone.getAvailableIDs()
.
获取可用时区列表(并选择最适合您的系统的时区)
您也可以使用系统的默认时区TimeZone.getDefault()
,但是这个,所以最好明确使用一个特定的时区。
要从 String
获得 Date
,请不要使用已弃用的构造函数 (new Date("09/10/2017 21:53:17")
)。最好使用 SimpleDateFormat
并设置此日期所指的时区。
在我所做的测试中,09/10/2017
被解释为“month/day/year”,所以我将使用相同的值。我也在考虑输入是 UTC,但您可以将其更改为您需要的任何时区:
String s = "09/10/2017 21:53:17";
SimpleDateFormat parser = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
// the input is in UTC (change it to the timezone you need)
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date d = parser.parse(s);
以上日期相当于 2017 年 9 月 10 日,在 UTC 的 21:53:17。如果输入的是其他时区,只需将“UTC”更改为相应的时区名称即可。
Check the javadoc SimpleDateFormat
.
使用的所有可能格式
Java新Date/TimeAPI
旧的 classes(Date
、Calendar
和 SimpleDateFormat
)有 lots of problems and design issues,它们正在被新的 APIs.
如果您使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java 6 或 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it ).
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes和方法名称是一样的。
最新的 JDBC 驱动程序已经支持新的 Java 8 种类型(检查您的驱动程序是否已经支持)。但是如果你还需要使用java.util.Date
,你可以很方便的将from/to转换成新的API.
在Java8中,Date
有新的from
和toInstant
方法,将from/to转换为新的java.time.Instant
class:
Date date = Date.from(instant);
Instant instant = date.toInstant();
在 ThreeTen Backport 中,您可以使用 org.threeten.bp.DateTimeUtils
class 转换 from/to org.threeten.bp.Instant
:
Date date = DateTimeUtils.toDate(instant);
Instant instant = DateTimeUtils.toInstant(date);
通过 Instant
,您可以轻松转换为您想要的任何时区(使用 ZoneId
class 将其转换为 ZonedDateTime
),然后使用 DateTimeFormatter
更改格式:
// convert Date to Instant, and then to a timezone
ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Asia/Kolkata"));
// format it
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = fmt.format(z);
System.out.println(formatted); // 2017-10-11 17:22:30
解析一个String
是相似的。您使用 DateTimeFormatter
,然后解析为 LocalDateTime
(因为输入 String
中没有时区),然后将其转换为时区(您可以选择转换如果你需要,它到 Date
):
String input = "09/10/2017 21:53:17";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
// parse the input
LocalDateTime dt = LocalDateTime.parse(input, parser);
// convert to a timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Asia/Kolkata"));
// you can format it, just as above
// you can also convert it to a Date
Date d = Date.from(z.toInstant());
如果要转换为 UTC,请使用常量 ZoneOffset.UTC
而不是 ZoneId
。此外,check the javadoc 有关格式的更多详细信息(它们并不总是与 SimpleDateFormat
使用的相同)。
我想在数据库中存储 UTC 时间(yyyy-mm-dd
或 dd-mm-yyyy
)
- 我想将本地时区转换为 UTC 并将其存储在数据库中
我尝试了不同的方法,但都不能正常工作。下面是我将本地转换为 UTC
的代码- 从 DB 获取 UTC 时间并转换为本地时区
下面是我的代码:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class TestDate {
public static void main(String[] args) {
/*Date de = new Date();
DateFormat converter1 = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
System.err.println(converter1.format(de));
Date der =*/
localToGMT();
// System.err.println("0000 : "+converter1.format(der));
Date d= new Date("09/10/2017 21:53:17");
gmttoLocalDate(d);
}
public static Date localToGMT() {
// Date gmt = new Date(sdf.format(date));
Date gmt = null;
Date localTime = new Date();
//creating DateFormat for converting time from local timezone to GMT
DateFormat converter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
//getting GMT timezone, you can get any timezone e.g. UTC
converter.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("local time : " + localTime);;
System.out.println("time in GMT : " + converter.format(localTime));
try {
gmt =converter.parse((converter.format(localTime)));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*Date date = new Date("2017/10/10 12:04:28");
System.err.println(date);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
gmt = sdf.parse(sdf.format(date));*/
System.err.println("converted to utc :" + gmt);
return gmt;
}
public static Date gmttoLocalDate(Date date) {
String timeZone = Calendar.getInstance().getTimeZone().getID();
Date local = new Date(date.getTime() + TimeZone.getTimeZone(timeZone).getOffset(date.getTime()));
System.err.println("converted to local timezone :" + local);
return local;
}
}
UTC 本地
public static Date localToUTC() {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date gmt = new Date(sdf.format(date));
return gmt;
}
UTC 到本地
public static Date utctoLocalDate(Date date) {
String timeZone = Calendar.getInstance().getTimeZone().getID();
Date local = new Date(date.getTime() + TimeZone.getTimeZone(timeZone).getOffset(date.getTime()));
return local
}
一个java.util.Date
has no timezone information。它只有一个 long
值,这是自 unix 纪元(即 1970-01-01T00:00:00Z
或 January 1st 1970 午夜以来的毫秒数在 UTC)。
这个值(自纪元以来的毫秒数)有
时间戳是一个“绝对”值,全世界都一样。
例子:我刚得到当前时间(System.currentTimeMillis()
),结果是1507722750315
(这是自纪元以来的当前毫秒数)。这个价值对世界上的每个人都是一样的。但是这个相同的值可以对应每个时区的不同date/time:
- 在UTC中对应
2017-10-11T11:52:30.315Z
- 在圣保罗(巴西),
2017-10-11T08:52:30.315-03:00
- 在伦敦,是
2017-10-11T12:52:30.315+01:00
- 在东京,
2017-10-11T20:52:30.315+09:00
- 在印度,是
2017-10-11T17:22:30.315+05:30
- 在奥克兰,
2017-10-12T00:52:30.315+13:00
(那里已经“明天”了) - 等等...
因此,当您执行接收 java.util.Date
并尝试将其转换为另一个 java.util.Date
的方法时,您没有转换任何东西。 Date
仅包含时间戳值(对应于特定时间点的“绝对”值)。但是Date
本身对时区一无所知,所以做这样的转换是没有意义的(全世界的时间戳都是一样的,不需要转换)。
“但是当我打印日期时,我看到的是本地时间的值”
嗯,这个就解释好了in this article。如果你 System.out.println
一个 Date
,或者记录它,或者在调试器中查看它的值,你会看到类似的东西:
Wed Oct 12 12:33:99 IST 2017
但那是因为隐式调用了 toString()
方法,并且此方法将时间戳值转换为 JVM 默认时区(因此它看起来像“本地 date/time”)。
但是请记住,这个 Wed Oct etc
字符串 而不是 Date
对象持有的实际值:它所拥有的只是对应于该对象的时间戳date/time 显示。但是日期对象本身没有任何本地 date/time 的概念,也没有任何时区相关信息。您看到的只是时间戳值的表示,以特定格式,针对特定时区。
那怎么办?
如果数据库字段是date类型,那么JDBC驱动一般会处理,所以直接保存Date
对象即可。无需关心格式和时区,因为 Date
没有格式,也没有任何时区信息。
日期类型的问题在于任何 language/database/vendor/application 都以不同的方式显示它。 Java 的 Date.toString()
将其转换为 JVM 默认时区,一些数据库以特定格式显示(dd/mm/yyyy,或 yyyy-mm-dd 等)并转换为在中配置的任何时区数据库等。
但请记住,日期本身没有格式。它只有一个值,问题是相同的日期可以 表示 不同的格式。示例:2017 年 10 月 15 日 可以表示为 2017-10-15
、10/15/2017
、15th Oct 2017
、15 de Outubro de 2017
(在 pt_BR(葡萄牙语)语言环境)等等。格式(表示)不同,但Date
值相同
所以,如果你正在处理 Date
对象,数据库字段是与日期相关的类型,它 returns 并保存 Date
对象,只需使用它直接。
如果你想显示这个日期,但是,(显示给用户,或记录它),或者如果数据库字段是String
(或varchar,或任何其他与文本相关的类型),那就完全不同了。
打印日期(或将其转换为 String
)时,您可以使用 SimpleDateFormat
:
// a java.util.Date with the same timestamp above (1507722750315)
Date date = new Date(1507722750315L);
// choose a format
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// choose a timezone to convert to
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
// convert to a String
String formattedDate = sdf.format(date);
System.out.println(formattedDate); // 2017-10-11 17:22:30
在这种情况下,输出是:
2017-10-11 17:22:30
如果我将时区更改为另一个时区,结果将转换为:
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
// convert to a String
String formattedDate = sdf.format(date);
System.out.println(formattedDate); // 2017-10-11 12:52:30
现在的结果是:
2017-10-11 12:52:30
但是 Date
值仍然相同:如果您调用 date.getTime()
,它将 return 时间戳值,它仍然是 1507722750315
。我刚刚更改了这个日期的表示(格式和时区)。但是 Date
本身的值没有改变。
另请注意,我使用了 IANA timezones names(始终采用 Region/City
格式,例如 Asia/Kolkata
或 Europe/Berlin
)。
避免使用 3 个字母的缩写(如 IST
或 CET
),因为它们是 ambiguous and not standard.
您可以通过调用 TimeZone.getAvailableIDs()
.
您也可以使用系统的默认时区TimeZone.getDefault()
,但是这个
要从 String
获得 Date
,请不要使用已弃用的构造函数 (new Date("09/10/2017 21:53:17")
)。最好使用 SimpleDateFormat
并设置此日期所指的时区。
在我所做的测试中,09/10/2017
被解释为“month/day/year”,所以我将使用相同的值。我也在考虑输入是 UTC,但您可以将其更改为您需要的任何时区:
String s = "09/10/2017 21:53:17";
SimpleDateFormat parser = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
// the input is in UTC (change it to the timezone you need)
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
Date d = parser.parse(s);
以上日期相当于 2017 年 9 月 10 日,在 UTC 的 21:53:17。如果输入的是其他时区,只需将“UTC”更改为相应的时区名称即可。
Check the javadoc SimpleDateFormat
.
Java新Date/TimeAPI
旧的 classes(Date
、Calendar
和 SimpleDateFormat
)有 lots of problems and design issues,它们正在被新的 APIs.
如果您使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java 6 或 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes和方法名称是一样的。
最新的 JDBC 驱动程序已经支持新的 Java 8 种类型(检查您的驱动程序是否已经支持)。但是如果你还需要使用java.util.Date
,你可以很方便的将from/to转换成新的API.
在Java8中,Date
有新的from
和toInstant
方法,将from/to转换为新的java.time.Instant
class:
Date date = Date.from(instant);
Instant instant = date.toInstant();
在 ThreeTen Backport 中,您可以使用 org.threeten.bp.DateTimeUtils
class 转换 from/to org.threeten.bp.Instant
:
Date date = DateTimeUtils.toDate(instant);
Instant instant = DateTimeUtils.toInstant(date);
通过 Instant
,您可以轻松转换为您想要的任何时区(使用 ZoneId
class 将其转换为 ZonedDateTime
),然后使用 DateTimeFormatter
更改格式:
// convert Date to Instant, and then to a timezone
ZonedDateTime z = date.toInstant().atZone(ZoneId.of("Asia/Kolkata"));
// format it
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = fmt.format(z);
System.out.println(formatted); // 2017-10-11 17:22:30
解析一个String
是相似的。您使用 DateTimeFormatter
,然后解析为 LocalDateTime
(因为输入 String
中没有时区),然后将其转换为时区(您可以选择转换如果你需要,它到 Date
):
String input = "09/10/2017 21:53:17";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
// parse the input
LocalDateTime dt = LocalDateTime.parse(input, parser);
// convert to a timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Asia/Kolkata"));
// you can format it, just as above
// you can also convert it to a Date
Date d = Date.from(z.toInstant());
如果要转换为 UTC,请使用常量 ZoneOffset.UTC
而不是 ZoneId
。此外,check the javadoc 有关格式的更多详细信息(它们并不总是与 SimpleDateFormat
使用的相同)。