1. el-date-picker 不同时区选择问题
问题
业务系统需要在不同的国家地区显示一样的时间. 但是el-date-picker组件默认是根据当前操作系统对应的时区显示时间
- 当在英国,电脑默认使用英国时区,
- 当前选择日期时间为: 2024-04-30 1:00:00 , 组件获取的日期对应时间戳为2024-04-30 1:00:00
- 当在中国, 电脑默认使用中国时区,
- 当前选择日期时间为: 2024-04-30 1:00:00 , 组件获取的日期对应时间戳为2024-04-30 8:00:00 所以最终不同的用户在不同的地区选择日期后,保存到后台的时间戳会不一致
时间的概念与工具
格林尼治标准时间
- 英国伦敦郊区的皇家格林尼治天文台的标准时间,本初子午线被定义在通过那里的经线, 为零度经线
- 地球表面按经线从左到右递增,每相隔15度划一个区域,这样一共有24个区域,每一个区域相差1小时
东8区
- 在地图上看: 从英国->中国,左->右 , 往右东边移动了8个区,时差7小时 (由于一个15度不一定刚好等于完整的一个小时)
- 地球自转的方向是自西向东, 从左到右. 即太阳先照到中国再照到英国, 中国的时间会比英国早7个小时
世界时间 (piliapp.com)
电脑时区选择地方
时间戳
通过时间戳的统一时间,时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数
时间戳有两种单位
- 毫秒
- 秒
由于业务只关心到秒,所以保存到后台只存秒单位数据.
moment.js
Moment.js 中文网 | 开发文档 (momentjs.cn)
moment工具简单好用 ,支持格式化 比较等
//转化:
//时间戳字符串(秒为单位) 转字符串格式化
let formatStr = moment.unix(300000).format('YYYY-MM-DD HH:mm:ss')
//把字符串转时间戳(单位秒)
let moment('2024-04-30 8:00:00').unix()
//把字符串转时间戳(单位毫秒)
let moment('2024-04-30 8:00:00')
//比较
let now = new Date()
moment('2024-04-30 8:00:00').isBefore(moment(now)) //是否小于现在
moment('2024-04-30 8:00:00').isAfter(moment(now)) //是否大于现在
方案
方案1:
让所有使用后台的用户都调整系统的时间时区(该方案不现实)
方案2:
直接存字符串,不存时间戳. 缺点:字符串无法做日期的比较, 需要做转化
方案3:
前端通过选择的内容获取字符串,然后根据当前字符串转换为时间戳,再给后台
el-date-picker 支持3种格式化获取时间的方式
DateTimePicker 日期时间选择器
我们可以看到选中相同的时间,访问的信息格式都是不一样的
- Date类型 (默认,不靠谱因为包含中国时间信息)
- value-format (字符串格式化 靠谱)
- 时间戳 (不靠谱,因为包含中国时间信息后再转成时间戳) 由于不同地区el-detapicker 会自动显示不同的当前日期时间,所以只能选择value-format
<el-date-picker
v-model="value_show"
type="datetime"
placeholder="Pick a Date"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<script lang="ts" setup>
import { ref } from 'vue'
const value_show = ref('') //这里记录的是UI选择的日期
let value = moment(value_show.value).unix() //把格式化显示字符串(不带时区)转成时间戳
// todo 这时候value 就可以提交给后台了
// 其他地方显示的时候只需要
moment.unix(value).format("YYYY-MM-DD HH:mm:ss")
</script>
2. ios时间处理问题
问题
ios 老一点的设备不支持 日期格式化 YYYY-MM-DD 的写法,只支持 YYYY/MM/DD
方案
通过正则把 - 替换为 / 即可
let start_time = '2024-04-20 11:30:10'
var stime = new Date(start_time.replace(/-/g, "/")).getTime();