在开发Android的过程中,出现过几次由于日期时间导致的问题,而且主要是由于时区的原因导致,所以一直想总结一下,形成一个良好的开发规范。

 
一、Unix时间戳
 
  Unix时间戳(Unix timestamp),或称Unix时间(Unix time)、POSIX时间(POSIX time),是一种时间表示方法,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。Unix时间戳不仅被使用在Unix系统、类Unix系统中,也在许多其他操作系统中被广泛采用。
 
二、关于时间标准和时区
 
  1、原子时:International Atomic Time (IAT)
 
    又称国际原子时,是一种通过原子钟得到的时间标准,原子钟是世界上已知最准确的时间测量和频率标准,原子钟在 37 亿年的误差不超过 1 秒。
 
  2、世界时:Universal Time(UT)
 
    是一种以格林尼治子夜起算的平太阳时。世界时是以地球自转为基准得到的时间尺度,其精度受到地球自转不均匀变化和极移的影响,为了解决这种影响,1955年国际天文联合会定义了UT0、UT1和UT2三个系统,他们三者之间是递进的关系,后者都是发现前者的一些度量差别,通过修正得到更均匀的时标。
 
    在格林尼治子午线上的平太阳时称为世界时(UT0),又叫格林尼治平时(GMT)。格林尼治标准时间(旧译格林尼治平均时间或格林威治标准时间,英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线。自1924年2月5日开始,格林尼治天文台每隔一小时会向全世界发放调时信息。
 
  2、协调世界时:Coordinated Universal Time(UTC)
 
    又称世界标准时间、世界统一时间。是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以“秒”为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密,因此若以“世界标准时间”的角度来说,UTC比GMT更精准。其误差值必须保持在0.9秒以内,若大于0.9秒则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。
 
    基本上UTC的本质强调的是比GMT更精确的世界时间标准,UTC中多一个闰秒的调整,以确保协调世界时(UTC)与格林尼治平时(GMT)相差不会超过0.9秒,并在有需要的时候在协调世界时(UTC)内加上正或负闰秒。
 
    UTC被应用在大多数的计算机以及网络标准中。
 
  3、夏令时与冬令时:Daylight Saving Time(DST)
 
    又称“日光节约时制”和“夏令时间”,是一种为节约能源而人为规定地方时间的制度,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮早的夏季人为将时间提前一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。目前全世界有近110个国家每年要实行夏令时。自2011年3月27日开始俄罗斯永久使用夏令时,把时间拨快一小时,不再调回。
 
    简单来说,使用夏令时和冬令时即在夏季将时间拨快一个小时,等到冬季再将时间拨慢一个小时。
 
  4、CST
 
    CST同时代表澳大利亚、美国、中国、古巴四个国家的标准时间,时区分别为:
 
     澳洲中部时间,Central Standard Time (Australia) UT+9:30
     中部标准时区(北美洲),Central Standard Time (North America) UT-6:00
     北京时间,China Standard Time UT+8:00
     古巴标准时间,Cuba Standard Time UT-4:00
 
  在开发时我们需要注意不同国家的时区,并且UTC和GMT在计算机系统中使用并无明显差别,可视为等同。
 
二、规范
 
  在实际开发中,当时间用于显示时,非特殊要求下一般使用系统默认的时区时间作为显示时间。将时间做为数据存储或传递给其他系统时(特别是跨平台调用),则最好使用标准的UTC/GMT时间(后面统称GMT),除非事先约定或标识了时间的类型。
 
三、在Android中需要特别注意的事项
 
  1、Android中表示日期时间的类型,有Date、Calendar,他们在没有显示设置其时区时,取到的当前时间均为系统默认时区的时间,即使给定一个时间,同样是按系统默认时区来换算时间,所以说他们都是与时区相关的。
 
  2、SimpleDateFormat对象本身也是跟时区相关。
 
    当使用parse将一个字符串格式的日期转换为Date对象,或者将一个Date对象转换为字符串日期时,这个字符串日期的时区以SimpleDateFormat关联的时区为准,如果通过setTimeZone修改了时区,则这个字符串日期以修改后的时区为准。例如:
 
// 2013-1-31 22:17:14
Date date = new Date(1359641834000L);
System.out.println(date);
String dateStr = "2013-1-31 22:17:14";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
try
{
    // 对于已经设定为GMT时间标准的dateFormat来说,一切需要他转换的字符串日期都是GMT标准时间,转换后返回的Date由于默认遵守系统默认时区,所以转换给Date的日期需要+8(例如北京标准时区),也就是时区与标准不同导致的时差。
    Date dateTmp = dateFormat.parse(dateStr);
    System.out.println(dateTmp);
catch (ParseException e) 
{
    e.printStackTrace();  
}  
// Date还是按系统默认时区,而format格式化处来的字符串是GMT,所以要-8。
String dateStrTmp = dateFormat.format(date);  
System.out.println(dateStrTmp);
    输出结果为:image
  3、Calendar在不手动设置时区时,是与系统默认时区相关的。在手动修改时区后,不能使用calendar.getTime方法来直接获取Date日期,因为此时的日期与setTime时的值相同,想要正确获取修改时区后的时间,应该通过calendar的get方法。例如:
 
Date date = new Date(1359641834000L);
System.out.println(date);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));  
// 或者可以 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));  
calendar.setTime(date);
System.out.println(calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE));
 
Calendar calendar2 = Calendar.getInstance();  
calendar2.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND));
 
System.out.println(calendar.getTime());  
System.out.println(calendar2.getTime());
    输入结果为:image
 
  4、TimeZone
 
    在开发中,我们可以通过TimeZone对象获取关于系统默认时区及其相关的详细信息。
 
四、Android关于日期的工具类
 
/**
 * Copyright (C) 2011, BHJ
 * All rights reserved.
 * 
 * 文件名称:
 * 文件标识:
 * 文件摘要:
 * 
 * 当前版本:
 * 作    者:
 * 完成日期:2013-12-20
 * 
 * 取代版本:
 * 修改时间:
 * 修 改 人:
 * 修改摘要:
 */
 
package com.bhj.timetest;
 
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
 
/**
 * 日期工具类(未特别说明的均为系统默认时区下的时间)
 * */
public class DateUtil
{    
    /** 1s==1000ms */
    private final static int TIME_MILLISECONDS = 1000;
    /** 时间中的分、秒最大值均为60 */
    private final static int TIME_NUMBERS = 60;
    /** 时间中的小时最大值 */
    private final static int TIME_HOURSES = 24;
    /** 格式化日期的标准字符串 */
    private final static String FORMAT = "yyyy-MM-dd HH:mm:ss";
    
    /**
     * 获取时区信息
     * */
    public static TimeZone getTimeZone()
    {
        return TimeZone.getDefault();
    }
    
    /**
     * 将日期字符串转换为Date对象
     * @param date 日期字符串,必须为"yyyy-MM-dd HH:mm:ss"
     * @return 日期字符串的Date对象表达形式
     * */
    public static Date parseDate(String date)
    {
        return parseDate(date, FORMAT);
    }
    
    /**
     * 将日期字符串转换为Date对象
     * @param date 日期字符串,必须为"yyyy-MM-dd HH:mm:ss"
     * @param format 格式化字符串
     * @return 日期字符串的Date对象表达形式
     * */
    public static Date parseDate(String date, String format)
    {
        Date dt = null;
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        try
        {
            dt = dateFormat.parse(date);
        }
        catch(ParseException e)
        {
            e.printStackTrace();
        }
        
        return dt;
    }
    
    /**
     * 将Date对象转换为指定格式的字符串
     * @param date Date对象
     * @return Date对象的字符串表达形式"yyyy-MM-dd HH:mm:ss"
     * */
    public static String formatDate(Date date)
    {
        return formatDate(date, FORMAT);  
    }
    
    /**
     * 将Date对象转换为指定格式的字符串
     * @param date Date对象
     * @param String format 格式化字符串
     * @return Date对象的字符串表达形式
     * */
    public static String formatDate(Date date, String format)
    {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);  
        return dateFormat.format(date);  
    }
 
    /**
     * 格式化日期
     * @param long unixTime unix时间戳
     * @return 日期字符串"yyyy-MM-dd HH:mm:ss"
     * */
    public static String formatUnixTime(long unixTime)
    {  
        return formatUnixTime(unixTime, FORMAT);
    }
    
    /**
     * 格式化日期
     * @param long unixTime unix时间戳
     * @param String format 格式化字符串
     * @return 日期字符串
     * */
    public static String formatUnixTime(long unixTime, String format)
    {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);  
        return dateFormat.format(unixTime);  
    }
    
    /**
     * 将GMT日期格式化为系统默认时区的日期字符串表达形式
     * @param gmtUnixTime GTM时间戳
     * @return 日期字符串"yyyy-MM-dd HH:mm:ss"
     * */
    public static String formatGMTUnixTime(long gmtUnixTime)
    {
        return formatGMTUnixTime(gmtUnixTime, FORMAT); 
    }
    
    /**
     * 将GMT日期格式化为系统默认时区的日期字符串表达形式
     * @param gmtUnixTime GTM时间戳
     * @param format 格式化字符串
     * @return 日期字符串"yyyy-MM-dd HH:mm:ss"
     * */
    public static String formatGMTUnixTime(long gmtUnixTime, String format)
    {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        return dateFormat.format(gmtUnixTime + TimeZone.getDefault().getRawOffset()); 
    }
    
    /**
     * 获取时间戳的Date表示形式
     * @param unixTime unix时间戳
     * @return Date对象
     * */
    public static Date getDate(long unixTime)
    {  
        return new Date(unixTime);  
    }
    
    /**
     * 获取GMT时间戳的Date表示形式(转换为Date表示形式后,为系统默认时区下的时间)
     * @param gmtUnixTime GMT Unix时间戳
     * @return Date对象
     * */
    public static Date getGMTDate(long gmtUnixTime)
    {
        return new Date(gmtUnixTime + TimeZone.getDefault().getRawOffset()); 
    }
 
    /**
     * 将系统默认时区的Unix时间戳转换为GMT Unix时间戳
     * @param unixTime unix时间戳
     * @return GMT Unix时间戳
     * */
    public static long getGMTUnixTime(long unixTime)
    {
        return unixTime - TimeZone.getDefault().getRawOffset();
    }
 
    /**
     * 将GMT Unix时间戳转换为系统默认时区的Unix时间戳
     * @param gmtUnixTime GMT Unix时间戳
     * @return 系统默认时区的Unix时间戳
     * */
    public static long getCurrentTimeZoneUnixTime(long gmtUnixTime)
    {
        return gmtUnixTime + TimeZone.getDefault().getRawOffset();
    }
    
    /**
     * 获取当前时间的GMT Unix时间戳
     * @return 当前的GMT Unix时间戳
     * */
    public static long getGMTUnixTimeByCalendar()
    {
        Calendar calendar = Calendar.getInstance();
        // 获取当前时区下日期时间对应的时间戳
        long unixTime = calendar.getTimeInMillis();
        // 获取标准格林尼治时间下日期时间对应的时间戳 
        long unixTimeGMT = unixTime - TimeZone.getDefault().getRawOffset();
        return unixTimeGMT;
    }
    
    /**
     * 获取当前时间的Unix时间戳
     * @return 当前的Unix时间戳
     * */
    public static long getUnixTimeByCalendar()
    {
        Calendar calendar = Calendar.getInstance();
        // 获取当前时区下日期时间对应的时间戳
        long unixTime = calendar.getTimeInMillis();
        return unixTime;
    }
    
    /** 
     * 获取更改时区后的时间 
     * @param date 时间 
     * @param oldZone 旧时区 
     * @param newZone 新时区 
     * @return 时间
     */  
    public static Date changeTimeZone(Date date, TimeZone oldZone, TimeZone newZone) 
    {  
        Date dateTmp = null;
        if (date != null)
        {
            int timeOffset = oldZone.getRawOffset() - newZone.getRawOffset();
            dateTmp = new Date(date.getTime() - timeOffset);
        }
        return dateTmp;
    }
    
    /**
     * 将总秒数转换为时分秒表达形式
     * @param seconds 任意秒数
     * @return %s小时%s分%s秒
     */
    public static String formatTime(long seconds)
    {
        long hh = seconds / TIME_NUMBERS / TIME_NUMBERS;
        long mm = (seconds - hh * TIME_NUMBERS * TIME_NUMBERS) > 0 ? (seconds - hh * TIME_NUMBERS * TIME_NUMBERS) / TIME_NUMBERS : 0;
        long ss = seconds < TIME_NUMBERS ? seconds : seconds % TIME_NUMBERS;
        return     (hh == 0 ? "" : (hh < 10 ? "0" + hh : hh) + "小时") 
                + (mm == 0 ? "" : (mm < 10 ? "0" + mm : mm) + "分") 
                + (ss == 0 ? "" : (ss < 10 ? "0" + ss : ss) + "秒");
    }
    
    /**
     * 获取当前时间距离指定日期时差的大致表达形式
     * @param long date 日期
     * @return 时差的大致表达形式
     * */
    public static String getDiffTime(long date)
    {
        String strTime = "很久很久以前";
        long time = Math.abs(new Date().getTime() - date);
        // 一分钟以内
        if(time < TIME_NUMBERS * TIME_MILLISECONDS)
        {
            strTime = "刚刚";
        }
        else
        {
            int min = (int)(time / TIME_MILLISECONDS / TIME_NUMBERS);
            if(min < TIME_NUMBERS)
            {
                if(min < 15)
                {
                    strTime = "一刻钟前";
                }
                else if(min < 30)
                {
                    strTime = "半小时前";
                }
                else
                {
                    strTime = "1小时前";
                }
            }
            else
            {
                int hh = min / TIME_NUMBERS;
                if(hh < TIME_HOURSES)
                {
                    strTime = hh + "小时前";
                }
                else
                {
                    int days = hh / TIME_HOURSES;
                    if(days <= 6)
                    {
                        strTime = days + "天前";
                    }
                    else
                    {
                        int weeks = days / 7;
                        if(weeks < 3)
                        {
                            strTime = weeks + "周前";    
                        }
                    }
                }
            }
        }
        
        return strTime;
    }
}

Android中关于日期时间与时区的使用总结的更多相关文章

  1. Android中实现日期时间选择器(DatePicker和TimePicker)

    利用Android应用框架提供的DatePicker(日期选择器)和TimePicker(时间选择器),实现日期时间选择器. Dialog的Content布局文件(date_time_dialog.x ...

  2. android 中 系统日期时间的获取

    import    java.text.SimpleDateFormat; SimpleDateFormat    formatter    =   new    SimpleDateFormat   ...

  3. 使用DateTimeOffset 对xml中的日期时间格式时区进行处理

    在日常使用中难免会与XML打交道,其中一个常用的格式就是日期了. 交互的时候通常有下面2种方式 DECLARE @Doc XML=' <R> <T>2018-02-22+08: ...

  4. Android实践 -- 设置系统日期时间和时区

    设置系统日期时间和时区 设置系统的日期时间和时区,需要 系统权限和系统签名,android:sharedUserId="android.uid.system" 需要在manifes ...

  5. 在mysql数据库中关于日期时间字段的处理

    在mysql数据库中关于日期时间字段的处理 在开发中,日期时间字段一般有如下几种设计 假设要获取2013-08-15日到2013-08-16日之间的记录 1. 直接使用日期时间类字段 相关sql语句如 ...

  6. JavaScript中的日期时间函数

    1.Date对象具有多种构造函数,下面简单列举如下 new Date() new Date(milliseconds) new Date(datestring) new Date(year, mont ...

  7. Solr中的日期/时间表示

    摘要: Solr的日期字段(TrieDateField 和DateRangeField)可以对一个时间点以毫秒精度表示. 格式 Solr中的日期有很严格的格式限制: YYYY-MM-DDThh:mm: ...

  8. MySQL 中的日期时间类型

    日期时间类型中包含以下几种数据类型: DATE TIME DATETIME TIMESTAMP YEAR 各类型都有具体的取值范围,超出或非法的其他值时,MySQL 会回退到 0.TIMESTAMP ...

  9. Oracle中与日期时间有关的运算函数

    1            ADD_MONTHS 格式:ADD_MONTHS(D,N) 说明:返回日期时间D加N月后对应的日期时间.N为正时则表示D之后:N为负时则表示为D之前:N为小数则会自动先删除小 ...

随机推荐

  1. 一:Html基本结构

    1:什么是Html(HTML 概念)? Html是 HyperText mark-up Language 的缩写,意思是:超文本标记语言 2.HTML的发展史? 1991年:出现Html1.0(不存在 ...

  2. SQLSERVER数据库中的 时间函数

    一.sql server日期时间函数 Sql Server中的日期与时间函数 1.  当前系统日期.时间 select getdate() 2. dateadd  在向指定日期加上一段时间的基础上,返 ...

  3. 深入理解ThreadLocal(转)(2015年06月11日)

    注明:转自:http://my.oschina.net/clopopo/blog/149368 学习一个东西首先要知道为什么要引入它,就是我们能用它来干什么.所以我们先来看看ThreadLocal对我 ...

  4. 浅谈sql 、linq、lambda 查询语句的区别

    浅谈sql .linq.lambda 查询语句的区别 LINQ的书写格式如下: from 临时变量 in 集合对象或数据库对象 where 条件表达式 [order by条件] select 临时变量 ...

  5. LinearLayout和RelativeLayout

    LinearLayout和RelativeLayout 共有属性:java代码中通过btn1关联次控件android:id="@+id/btn1" 控件宽度android:layo ...

  6. 番外篇 之 C#委托

    对于上一节 番外篇之C#多线程的反思 反思一:   Thread th = new Thread(参数); ////参数的总结 ////首先,第一情况,对于 Thread th = new Threa ...

  7. Sublime Python 插件配置合集

    Python PEP8 Autoformat 插件 这是用来按PEP8自动格式化代码的.可以在包管理器中安装.快捷键 CTRL+SHIFT+R 自动格式化python代码 { "auto_c ...

  8. 安装包安装服务,点修复出现的错误”Error 1001:指定的服务已存在“ 解决办法

    安装项目下,右键视图->自定义操作,出现安装.提交.回滚.卸载四个文件夹,右键安装,添加自定义操作,选择安装的服务为输出文件 右键安装输出文件->在condition->Not (I ...

  9. oracle删除字段时候判断字段是否存在

    declare v_count number; begin ) into v_count from all_tab_columns a where a.TABLE_NAME = 'XXX1' and ...

  10. 利用kvc对UITabBar上的UITabBarButton的尝试修改.md

    一.前言 一次比较懒的想法,不想自定义UITabBar,也不想用第三方框架,于是想尝试修改苹果私有类来达到部分效果 效果如下 点击tabBar 上的按钮,图片有变大再变小的动画 tabBar 上某个按 ...