【时间和时区】Date与String

本文深入探讨Java中Date对象的内部存储机制,解释了Date对象实际上存储的是自1970年1月1日以来的毫秒数,而非具体的年月日时分秒。文章还详细介绍了时区的概念,以及Date对象如何实现时区无关性,同时提供了Date与String格式互转的具体代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Date中保存的是什么

在java中,只要我们执行

Date date = new Date();

就可以得到当前时间。如:

Date date = new Date();
System.out.println(date);

输出结果是: Thu Aug 24 10:15:29 CST 2017

也就是我执行上述代码的时刻:2017年8月24日10点15分29秒。是不是Date对象里存了年月日时分秒呢?不是的,Date对象里存的只是一个long型的变量,其值为自1970年1月1日0点至Date对象所记录时刻经过的毫秒数,调用Date对象getTime()方法就可以返回这个毫秒数,如下代码:

Date date = new Date();
System.out.println(date + ", " + date.getTime());

输出结果是: Thu Aug 24 10:48:05 CST 2017, 1503542885955

即上述程序执行的时刻是2017年8月24日10点48分05秒,该时刻距离1970年1月1日0点经过了1503542885955毫秒。反过来说,输出的年月日时分秒其实是根据这个毫秒数来反算出来的。

 

时区的概念

全球分为24个时区,相邻时区时间相差1个小时。比如北京处于东八时区,东京处于东九时区,北京时间比东京时间晚1个小时,而英国伦敦时间比北京晚7个小时(英国采用夏令时时,8月英国处于夏令时)。比如此刻北京时间是2017年8月24日11:17:10,则东京时间是2017年8月24日12:17:10,伦敦时间是2017年8月24日4:17:10。调用Date对象getTime()方法就可以返回这个毫秒数。

 

Date的时区无关性

既然Date里存放的是当前时刻距1970年1月1日0点时刻的毫秒数,如果此刻在伦敦、北京、东京有三个程序员同时执行如下语句:

Date date = new Date();

那这三个date对象里存的毫秒数是相同的吗?还是北京的比东京的小3600000(北京时间比东京时间晚1小时,1小时为3600秒即3600000毫秒)?答案是,这3个Date里的毫秒数是完全一样的。

确切的说,Date对象里存的是自格林威治时间( GMT)1970年1月1日0点至Date对象所表示时刻所经过的毫秒数。所以,如果某一时刻遍布于世界各地的程序员同时执行new Date语句,这些Date对象所存的毫秒数是完全一样的。也就是说,Date里存放的毫秒数是与时区无关的

 

 

Date 与  Sting 格式互转:

package utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * Date 和  String
 * 关于时间的格式,在应用中一般用 Stirng 和 Date 来表示,
 *
 * Date--> String 没有时区的概念,Date中的内容都是 国际的,当getHour() toString() 等方法时,
 * 通过 获取本地的时区对Date进行格式转换再输出
 * 
 * String --> Date 时,传递的 String,默认是本地的时区时间,如果传递的参数不是本地时区时间时,
 * 在转换为 Date时,需要指定时区
 */
public class Test_TimeZone {

	public static void main(String[] args) throws ParseException {
		
		Date date = new Date();
		System.out.println(date.getTime());  // 全球统一值
		System.out.println(date.toString()); // toString的时候获取本地时区,做了时间转换,并不是Date的真实时间
		System.out.println();
		
		String date_str_1 = format(date);
		System.out.println(date_str_1);
		
		Date date_1 = parse(date_str_1);
		System.out.println(date_1.toString());
	
		/*  查看 支持的 TimeZone
		String[] ss = TimeZone.getAvailableIDs();
		for (String string : ss) {
			if (string.indexOf("GMT") > 0) {
				System.out.println(string);
			}
		}
		*/
	}
	
	/**
	 * 日期格式转字符串   (Date -- > String)
	 * Date 转字符串,格式随便定义都可以
	 */
	public static String format(Date date) throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//df.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		//df.setTimeZone(TimeZone.getTimeZone("Etc/GMT-8"));
		df.setTimeZone(TimeZone.getTimeZone("GMT")); // 国际时间,决定输出的 String 是国际格式

		return df.format(date);
	}
	/**
	 * 字符串转日期格式    (String --> Date)
	 */
	public static Date parse(String s) throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//df.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		//df.setTimeZone(TimeZone.getTimeZone("Etc/GMT-8")); 
		df.setTimeZone(TimeZone.getTimeZone("GMT")); // 指定参数 String为国际格式,输出时,按本地时区输出
		
		return df.parse(s);
	}
}

 

将 某个时区 的 String 格式 转换为 另一个时区的 String 格式

package utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class Test_Time {

	public static void main(String[] args) throws ParseException {
		parse_format();
	}
	/**
	 * 将 某个时区的 String 的格式 转换为 另一个时区的 String 格式 
	 * @throws ParseException
	 */
	public static void parse_format() throws ParseException {

		String timeStr = "2017-8-24 11:17:10";
		/* 
		 * 一般是通过 Date 转换过来的,Date 转换到 String 的时候 需要指定时区,所以得到的String是有时区的
		 * (当你此刻输入一个 String 格式的时间时,这个String一定是有时区的,所以 要深刻理解 String 是有时区的,
		 *  任何时候需要操作该值的时候,都要指定 String 代表的时区)
		 */
		
		SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		bjSdf.setTimeZone(TimeZone.getTimeZone("GMT"));  
		/*
		 *  指定 字符串的时区
		 *  将字符串时间按 国际时间 解析成Date对象
		 *  (因为你通过其他地方获取的 String 是国际时间格式,所以按照国际时间转换)
		 */
		Date date = bjSdf.parse(timeStr); 
		System.out.println(date.getTime());   
		/*  
		 * 如果你获取的 是 本地的字符串时间,那就需要按照 本地的 时区转换,
		 * 转换成功之后,获取的Date都是国际格式,但是在 toString的时候,会默认按本地时区输出,但是输出内容并不是国际时间,
		 *
		 * 但getTime()是统一的,所以我们认为 Date 没有时区的概念,任何的输出操作都会先获取本地时区,将国际时间格式的Date,按本地时区输出。(输出内容不可信)
		 */ 
		SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 东京
		tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo")); // 设置东京时区
		System.out.println("国际时间: " + timeStr + " 对应的东京时间为:" + tokyoSdf.format(date));
		/*
		 *  输出:
		 *    1503573430000
		 *    国际时间: 2017-8-24 11:17:10 对应的东京时间为:2017-08-24 20:17:10
		 * */
	}

}

 

我觉得这两个例子,应该就能说明大部分问题了,

深刻理解 Date 没有时区的概念,任何的输出信息都是根据本地时区来输出的。

任何一个 String 格式的字符串都有相对应的时区,因为任何的String都是通过 new Date() 和  format() 转换过来的,即使没有写时区,当时默认也获取了本地时区。所以,Sting 一定有对应的时区。

 

 

参考博客:

https://blog.csdn.net/halfclear/article/details/77573956

https://www.cnblogs.com/softidea/p/8612287.html

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值