【从菜鸟到高手】日期格式化

本文深入探讨了软件中日期格式化的关键概念,包括日期在不同软件层次中的表现形式及其转换,详细讲解了UTC时间与本地时间的关系及转换方法,提供了Java、JS、Python等主流编程语言中日期格式化的具体实现技巧。

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

1 软件中的日期格式化

日期格式化就是对日期字符串进行解析和格式化输出。

在软件系统中,日期的形式与其被使用的阶段密切相关,展现层的日期数据为字符串,逻辑层的日期数据为 Date 对象,存储层的日期数据为时间戳或者数据库提供的 Date 类型,有时候也直接存储为日期字符串。

日期格式化就是在不同层次之间进行数据转换!

时间戳 <=> Date 对象 <=> 格式化字符串

2 UTC 时间与本地时间的关系

UTC(Universal Time Coordinated) 是世界统一时间, GMT(Greenwich MeanTime) 格林尼治时间,UTC 与 GMT 的含义完全相同。

UTC + 时区差 = 本地时间

例如,本地(北京)时间是0325 (凌晨3点25分),那么,UTC就是 0325 - 0800 = -0475,负号意味着是前一天, -0475 + 2400= 1925,既前一天的晚上7点25分。

中国与UTC的时差均为+8,也就是UTC+8。

js 代码

d = new Date() // Mon Oct 15 2018 18:15:31 GMT+0800 (中国标准时间)
d.toUTCString() // "Mon, 15 Oct 2018 10:15:31 GMT"

时间戳的概念:为当前时刻减去UTC时间(1970.1.1)零点时刻的秒数差,与当前系统所处的时区无关,同一时刻不管在任何时区下得到的时间戳都是一样的。

python 代码

import datetime
dt = datetime.datetime.now()            #获取本地当前时间
dt.timestamp()                  #获取时间戳

timestamp = datetime.datetime.now(timezone.utc).timestamp()
datetime.datetime.fromtimestamp(timestamp) # 通过timestamp得出datetime和utc datetime
datetime.datetime.fromtimestamp(timestamp,timezone.utc)    # 通过timestamp utc datetime  
  • 此方式下now()函数中有个参数为tz,参数意思为时区信息,不设时为本地时间,当设置时,如tz=timezone.utc,则表示为当前的utc时间,无论是utc时间还是本地时间,获得的时间戳都是同一个值.
  • timestamp()内部会根据时区设置得到时间戳,当时区为utc时间时timestamp()函数直接减去EPOCH得到的秒数,当为其他时区的时间时通过标准C库函数mktime得到相差秒数,不管哪种方式,相差的秒数差是一样的,所以不同时区下的时间戳必定为同一个值。

3 Java 日期格式化

SimpleDateFormat 是非线程安全的,在多并发情况下会抛 java.lang.NumberFormatException: multiple points,或者是格式化时间错误。

正确的使用方式:

  1. 每次都创建不同的 SimpleDateFormat 对象,适用于接口的调用频率很低的场景:
    public static  String formatDate(Date date)throws ParseException{
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }
    
    public static Date parse(String strDate) throws ParseException{
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.parse(strDate);
    }
  1. 使用同步或锁: 适用于高并发且多短命线程的场景:
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      
    public static String formatDate(Date date)throws ParseException{
        synchronized(sdf){
            return sdf.format(date);
        }  
    }
    
    public static Date parse(String strDate) throws ParseException{
        synchronized(sdf){
            return sdf.parse(strDate);
        }
    } 
  1. 使用 ThreadLocal 变量,适用于高并发且线程生命较为持久的场景
    // private static ThreadLocal<DateFormat> localsdf = new ThreadLocal<DateFormat>() {
    //     @Override
    //     protected DateFormat initialValue() {
    //         return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    //     }
    // };

    private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(); 

    public static DateFormat instance(String format)   //"yyyy-MM-dd HH:mm:ss"
    {  
        DateFormat df = threadLocal.get();  
        if(df==null){  
            df = new SimpleDateFormat(format);  
            threadLocal.set(df);  
        }  
        return df;  
    }  

    public static Date parse(String dateStr) throws ParseException {
        return localsdf.get().parse(dateStr);
    }

    public static String format(Date date) {
        return localsdf.get().format(date);
    }
  1. 使用其他类库中线程安全的时间格式化类

Apache Commons: FastDateFormat

4 JS 日期格式化

JS 没有提供原生的 format 方法,需要框架来实现:
例如:

/*   
函数:格式化日期   
参数:formatStr-格式化字符串   
d:将日显示为不带前导零的数字,如1   
dd:将日显示为带前导零的数字,如01   
ddd:将日显示为缩写形式,如Sun   
dddd:将日显示为全名,如Sunday   
M:将月份显示为不带前导零的数字,如一月显示为1   
MM:将月份显示为带前导零的数字,如01  
MMM:将月份显示为缩写形式,如Jan  
MMMM:将月份显示为完整月份名,如January  
yy:以两位数字格式显示年份  
yyyy:以四位数字格式显示年份  
h:使用12小时制将小时显示为不带前导零的数字,注意||的用法  
hh:使用12小时制将小时显示为带前导零的数字  
H:使用24小时制将小时显示为不带前导零的数字  
HH:使用24小时制将小时显示为带前导零的数字  
m:将分钟显示为不带前导零的数字  
mm:将分钟显示为带前导零的数字  
s:将秒显示为不带前导零的数字  
ss:将秒显示为带前导零的数字  
l:将毫秒显示为不带前导零的数字  
ll:将毫秒显示为带前导零的数字  
tt:显示am/pm  
TT:显示AM/PM  
返回:格式化后的日期  
*/ 
Date.prototype.format = function (formatStr) {  
    var date = this;  
    /*  
    函数:填充0字符  
    参数:value-需要填充的字符串, length-总长度  
    返回:填充后的字符串  
    */ 
    var zeroize = function (value, length) {  
        if (!length) {  
            length = 2;  
        }  
        value = new String(value);  
        for (var i = 0, zeros = ''; i < (length - value.length); i++) {  
            zeros += '0';  
        }  
            return zeros + value;  
    };  
    return formatStr.replace(/"[^"]*"|'[^']*'|\b(?:d{1,4}|M{1,4}|yy(?:yy)?|([hHmstT])\1?|[lLZ])\b/g, function($0) {  
        switch ($0) {  
            case 'd': return date.getDate();  
            case 'dd': return zeroize(date.getDate());  
            case 'ddd': return ['Sun', 'Mon', 'Tue', 'Wed', 'Thr', 'Fri', 'Sat'][date.getDay()];  
            case 'dddd': return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][date.getDay()];  
            case 'M': return date.getMonth() + 1;  
            case 'MM': return zeroize(date.getMonth() + 1);  
            case 'MMM': return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getMonth()];  
            case 'MMMM': return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][date.getMonth()];  
            case 'yy': return new String(date.getFullYear()).substr(2);  
            case 'yyyy': return date.getFullYear();  
            case 'h': return date.getHours() % 12 || 12;  
            case 'hh': return zeroize(date.getHours() % 12 || 12);  
            case 'H': return date.getHours();  
            case 'HH': return zeroize(date.getHours());  
            case 'm': return date.getMinutes();  
            case 'mm': return zeroize(date.getMinutes());  
            case 's': return date.getSeconds();  
            case 'ss': return zeroize(date.getSeconds());  
            case 'l': return date.getMilliseconds();  
            case 'll': return zeroize(date.getMilliseconds());  
            case 'tt': return date.getHours() < 12 ? 'am' : 'pm';  
            case 'TT': return date.getHours() < 12 ? 'AM' : 'PM';  
        }  
    });  
}

document.writeln(new Date().format("yyyy-MM-dd hh:mm:ss"));  

5 Python 日期格式化

Python 处理日期主要使用 time,datetime 两个库

import time
import datetime

t = "2017-11-24 17:30:00"
struct_time1 = time.strptime(t, "%Y-%m-%d %H:%M:%S")
time_stamp = int(time.mktime(struct_time1))

struct_time2 = time.localtime(timeStamp)

format_time1 = time.strftime("%Y-%m-%d %H:%M:%S", struct_time2) 
format_time2 = time.strftime("%Y/%m/%d %H:%M:%S", struct_time2)

now_timestamp = int(time.time())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值