If heart is sunny

在正式开始前优先要介绍一下 时区 ,1884年 国际经度会议将地球表面按经线等分为24 区,即以本初子午线为基准, 东西经度各7.5 度的范围作为零时区, 然后每隔15度为一时区,每个时区相差一小时

中国时区横跨东五区、东六区、东七区、东八区、东九区等五个地理时区;自西元1949年起,在中国大陆、台湾、香港、澳门所使用的 标准时间皆为东八区(UTC+8)时间,比协调世界时间(UTC)或格林尼治标准时间(GMT)快8小时

由于历史及政治因素,上述各地维持各自的时间标准及时区名称

中国大陆的时间标准:北京时间 (北京时区为东八区,要比零时区早8个小时。如果现在零时区的时间是10点的话,那北京时间就是18点)

台湾的时间标准称为中原标准时间或国家标准时间:台湾时间或台北时间

香港的时间标准:香港时间

澳门的时间标准:澳门标准时间

我们平时在程序里面所见到的 UTC 时间,就是零时区的时间,它的全称是Coordinated Universal Time ,即世界协调时间。另一个常见的缩写是 GMT ,即格林威治标准时间,格林威治位于 零时区,因此,我们平时说的UTC时间和GMT时间在数值上面都是一样的。

UTC(世界标准时间)

协调世界时,又称世界标准时间或世界协调时间,简称UTC(从英文“Coordinated Universal Time”/法文“Temps
Universel Coordonné”而来),是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。

GMT(格林尼治平时)

格林尼治平时(又称格林尼治平均时间或格林尼治标准时间,旧译格林威治标准时间;英语:Greenwich Mean
Time,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。

理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间;

由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能与实际的太阳时有误差,最大误差达16分钟

由于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治时间已经不再被作为标准时间使用。现在的标准时间,是由原子钟报时的协调世界时(UTC)

CST(北京时间)

北京时间,China Standard Time,中国标准时间。在时区划分上,属东八区,比协调世界时早8小时, 记为UTC+8

不过这个CST这个缩写比较纠结的是它可以同时代表四个不同的时间:
Central Standard Time (USA) UT-6:00
Central Standard Time (Australia) UT+9:30
China Standard Time UT+8:00
Cuba Standard Time UT-4:00

12、24小时制

格式化时间为12和24小时制

 Date date=new Date();
 //转换成时间格式12小时制
 SimpleDateFormat df_12=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
 //转换成时间格式24小时制
 SimpleDateFormat df_24=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 System.out.println("12小时制时间:"+df_12.format(date));
 System.out.println("24小时制时间:"+df_24.format(date));
 12小时制时间:2017-12-07 03:55:04 
 24小时制时间:2017-12-07 15:55:04

时间更新机制

设备上一般都自动更新系统时间,主要有以下俩种更新机制

NITZ(Network Identity and Time Zone,网络标识和时区),是一种用于自动配置本地的时间和日期的机制,同时也通过无线网向移动设备提供运营商信息

NITZ是自从PHASE 2+ RELEASE 96 的GSM中的可选功能,经常被用来自动更新移动电话的系统时钟

NITZ需要运营商网络支持(通过CS网络),目前国内电信、移动都支持NITZ方式更新时间日期,而联通目前可能不支持

NTP:NTP(Network Time Protocol)提供准确时间,首先要有准确的时间来源,这一时间应该是国际标准时间UTC。

NTP获得UTC的时间来源可以是原子钟、天文台、卫星,也可以从Internet上获取。这样就有了准确而可靠的时间源。时间按NTP服务器的等级传播。

NTP与NITZ不同的是,NTP需要从专门的NTP服务器来获取时间,只要手机连接上网络,都可以实现时间的更新。

package com.nk.machine.model;
import java.text.DateFormat;
import java.util.Date;
import java.util.TimeZone;
 * @author MrLiu
 * @date 2020/9/24
 * desc
public class TimeZoneTest {
    public static void main(String[] args) {
		//测试创建TimeZone对象的3种方法
        showUsageOfTimeZones();
		//测试TimeZone的其它API
        testOtherAPIs();
		//打印getTimeZone(String id)支持的所有id
		//printAllTimeZones() ;
     * 测试创建TimeZone对象的3种方法
    public static void showUsageOfTimeZones() {
        TimeZone tz;
        // (01) 默认时区
        tz = TimeZone.getDefault();
        printDateIn(tz);
        // (02) 设置时区为"GMT+08:00"
        tz = TimeZone.getTimeZone("GMT+08:00");
        printDateIn(tz);
        // (03) 设置时区为""
        tz = TimeZone.getTimeZone("Asia/Chongqing");
        printDateIn(tz);
     * 打印 tz对应的日期/时间
    private static void printDateIn(TimeZone tz) {
        //date为2013-09-19 14:22:30
        Date date = new Date(113, 8, 19, 14, 22, 30);
        // 获取默认的DateFormat,用于格式化Date
        DateFormat df = DateFormat.getInstance();
        // 设置时区为tz
        df.setTimeZone(tz);
        // 获取格式化后的字符串
        String str = df.format(date);
        System.out.println(tz.getID() + " :" + str);
     * 测试TimeZone的其它API
    public static void testOtherAPIs() {
        // 默认时区
        TimeZone tz = TimeZone.getDefault();
        // 获取“id”
        String id = tz.getID();
        // 获取“显示名称”
        String name = tz.getDisplayName();
        // 获取“时间偏移”。相对于“本初子午线”的偏移,单位是ms。
        int offset = tz.getRawOffset();
        // 获取“时间偏移” 对应的小时
        int gmt = offset / (3600 * 1000);
        System.out.printf("id=%s, name=%s, offset=%s(ms), gmt=%s\n",
                id, name, offset, gmt);
     * 打印getTimeZone(String id)支持的所有id
    public static void printAllTimeZones() {
        String[] ids = TimeZone.getAvailableIDs();
        for (String id : ids) {
            //int offset = TimeZone.getTimeZone(avaIds[i]).getRawOffset();
            //System.out.println(i+" "+avaIds[i]+" "+offset / (3600 * 1000) + "\t");
            System.out.printf(id + ", ");
        System.out.println();

修改系统时间

Here:如果需要修改系统时间,则首先需要将机器root权限,用到的场景相对较少

Andorid 代码

方式一:getSystemService系统服务

 Calendar c = Calendar.getInstance();
 // 年 月-1 日 时 分 秒
 if (date != null) {
   int year = date.getYear() + 1900;
   int day = date.getDate();
   int month = date.getMonth();
   int hour = date.getHours();
   int minutes = date.getMinutes();
   int seconds = date.getSeconds();
   c.set(year, month, day, hour, minutes, seconds);
 AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
 am.setTime(c.getTimeInMillis());

方式二:DataOutputStream日期输入

        try {
            Process process = Runtime.getRuntime().exec("su");
            // 测试的设置的时间【时间格式】
            String datetime = "20131023.112800"; 
            // yyyyMMdd.HHmmss
            DataOutputStream os = new DataOutputStream(process
                    .getOutputStream());
            os.writeBytes("setprop persist.sys.timezone GMT\n");
            os.writeBytes("/system/bin/date -s "
                    + datetime + "\n");
            os.writeBytes("clock -w\n");
            os.writeBytes("exit\n");
            os.flush();
            Toast.makeText(MainActivity.this, "系统时间同步成功",Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            Toast.makeText(MainActivity.this,
                    "系统时间同步失败,可能没有ROOT权限?", Toast.LENGTH_SHORT).show();
            e.printStackTrace();

方式三:代码中调用cmd命令

* @param cmd 命令 private static void execSuCmd(String cmd) { Process process = null; DataOutputStream os = null; DataInputStream is = null; try { process = Runtime.getRuntime().exec("su"); os = new DataOutputStream(process.getOutputStream()); os.writeBytes(cmd + "\n"); os.writeBytes("exit\n"); os.flush(); int aa = process.waitFor(); is = new DataInputStream(process.getInputStream()); byte[] buffer = new byte[is.available()]; is.read(buffer); String out = new String(buffer); } catch (Exception e) { e.printStackTrace(); } finally { try { if (os != null) { os.close(); if (is != null) { is.close(); if (process != null) { process.destroy(); } catch (Exception e) {
 String curr_time =052514412019.52”;
 execSuCmd("date " + curr_time + "\n busybox hwclock -w\n");

扩展:Android有专属的 NetworkTimeUpdateServcie系统服务 来负责更新系统时间,该服务在系统启动时在SystemServer.java中被创建

    if (!disableNetwork && !disableNetworkTime) {
        try {
            Slog.i(TAG, "NetworkTimeUpdateService");
            networkTimeUpdater = new NetworkTimeUpdateService(context);
       } catch (Throwable e) {
            reportWtf("starting NetworkTimeUpdate service", e);
    try {
        if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
    } catch (Throwable e) {
        reportWtf("Notifying NetworkTimeService running", e);
cmd 命令

shell命令

 #格式为date MMddHHmmyyyy.ss set
 date 123012002018.59 set

如需使用UTC时间,则需要加上-u选项

如果需要同步更新到硬件RTC中,则还需要使用hwclock

usage: hwclock [-rswtluf]
# hwclock -w –从系统时间设置到硬件时钟
# hwclock -s –从硬件时钟设置到系统时间
-f FILE Use specified device file instead of /dev/rtc (--rtc)
-l Hardware clock uses localtime (--localtime)
-r Show hardware clock time (--show)
-s Set system time from hardware clock (--hctosys)
-t Set the system time based on the current timezone (--systz)
-u Hardware clock uses UTC (--utc)
-w Set hardware clock from system time (--systohc)

时区设置,new Date()和系统时间相差8个小时

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class GetNowDate {
    //获取系统当前时间,字符串类型
    public static String getStrDate() {
        SimpleDateFormat format= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //设置为东八区
        format.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        Date newDate = new Date();
        String dateStr = sdf.format(newDate);
        return dateStr;
    //获取系统当前时间Date类型,需要将字符串类型转成时间
    public static Date getDaDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //设置为东八区
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        Date date = new Date();
        String dateStr = sdf.format(date);
        //将字符串转成时间
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date newDate = null;
        try {
            newDate = df.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        return newDate;

相互转换时区、时间

SimpleDateFormat:Date、字符串相互转换,格式化时间、解析时间

  //字符串转Date
  String stringDate = "Thu Oct 16 07:13:48 GMT 2015";
  SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM ddHH:mm:ss 'GMT' yyyy",Locale.US);
  Date date = sdf .parse(stringDate);
  System.out.println(date.toString());
  //Date转字符串
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    
  System.out.println(sdf .format(new Date()));
  //格式化时间
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
  String time = sdf.format(new Date());
  System.out.println(time);
  //解析时间 2016-01-05T15:06:58+0800
  Date date = sdf.parse(time);
  System.out.println(date);
  //T代表后面跟着时间,Z代表UTC统一时间
  //格式化时间
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
  String time = sdf.format(new Date());
  System.out.println(time);
  //解析时间 2016-01-05T15:09:54Z
  Date date = sdf.parse(time);
  System.out.println(date);

Date:时区、时间转换

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class TestTime {
public static void main(String[] args) {
	try {
        //获取Date对象,存放的是时间戳
        Date date = new Date();
        //获取时间戳(毫秒)
        long seconds = date.getTime();
        System.out.println("当前时间戳: " + seconds);
        //当前GMT(格林威治)时间、当前计算机系统所在时区的时间
        SimpleDateFormat beijingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("本地(东八区)时间: " + beijingFormat.format(date) +"; GMT时间: " + date.toGMTString());
        //东八区时间转换成东九区(东京)时间,比北京早一个小时
        SimpleDateFormat tokyoFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        tokyoFormat.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));
        System.out.println("东京(东九区)时间: "+tokyoFormat.format(date));
        //时间戳转化成Date
        SimpleDateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String fotmatString = timestampFormat.format(seconds);
        Date parseDate = timestampFormat.parse(fotmatString);
        System.out.println("时间戳转化成Date之后的时间: "+parseDate + ";格式化之后的: "+ fotmatString);
	} catch (Exception e) {
		e.printStackTrace();

TestLocalTime (Java8工具类)

import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; public class TestLocalTime { public static void main(String[] args) { //获取当前时区的日期 LocalDate localDate = LocalDate.now(); System.out.println("localDate: " + localDate); LocalTime localTime = LocalTime.now(); System.out.println("localTime: " + localTime); //根据上面两个对象,获取日期时间 LocalDateTime localDateTime = LocalDateTime.of(localDate,localTime); System.out.println("localDateTime: " + localDateTime); //使用静态方法生成此对象 LocalDateTime localDateTime2 = LocalDateTime.now(); System.out.println("localDateTime2: " + localDateTime2); //格式化时间 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss"); System.out.println("格式化之后的时间: " + localDateTime2.format(formatter)); //转化为时间戳(秒) long epochSecond = localDateTime2.toEpochSecond(ZoneOffset.of("+8")); //转化为毫秒 long epochMilli = localDateTime2.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli(); System.out.println("时间戳为:(秒) " + epochSecond + "; (毫秒): " + epochMilli); //时间戳(毫秒)转化成LocalDateTime Instant instant = Instant.ofEpochMilli(epochMilli); LocalDateTime localDateTime3 = LocalDateTime.ofInstant(instant, ZoneOffset.systemDefault()); System.out.println("时间戳(毫秒)转化成LocalDateTime: " + localDateTime3.format(formatter)); //时间戳(秒)转化成LocalDateTime Instant instant2 = Instant.ofEpochSecond(epochSecond); LocalDateTime localDateTime4 = LocalDateTime.ofInstant(instant2, ZoneOffset.systemDefault()); System.out.println("时间戳(秒)转化成LocalDateTime: " + localDateTime4.format(formatter));

关闭自动同步,实现自定同步

修改系统,时间戳出现8小时差的问题,首先设置的之后采用东八区GMT+8配置,可通过类型mCalendar.setTimeZone(TimeZone.getTimeZone("GMT+8"));进行设置,但是因时间戳无法跟随时区进行变化,所以在设置时间时,如果出现问题可以尝试先减去8*60*60*100的8小时差

root权限,且在AndroidManifest.xml里面加入以下配置

<uses-permission android:name="android.permission.SET_TIME" />

示例demo

    SimpleDateFormat format=new SimpleDateFormat("yyyyMMdd.HHmmss");
    //time是从服务器拿到的时间戳
    Long t=new Long(time);
    t=t-8*60*60*1000;
    Date date=new Date(t);
    String datetime=format.format(date);
    try {  
        Process process = Runtime.getRuntime().exec("su");
        DataOutputStream os = new DataOutputStream(process.getOutputStream());  
        os.writeBytes("setprop persist.sys.timezone GMT\n");  
        //把时间设置进去,这个地方一定要是yyyyMMdd.HHmmss的形式
        os.writeBytes("/system/bin/date -s "+datetime+"\n");  
        os.writeBytes("clock -w\n");  
        os.writeBytes("exit\n");  
        os.flush(); 
    } catch (IOException e) {
        e.printStackTrace();
        return false;
复制代码
  •