js的Date.parse()方法和getTime()的陷阱

之前一直记得getTime()和Date.parse()方法都是返回某个时间到1970年1月1日0:00的毫秒数,但是这次遇到了问题。
当我使用Date.parser()的时候,返回的却是这个时间点到1970年1月1日08:00的毫秒数。下面是我的代码:

function startTime() {
    let date = new Date,
        year = date.getFullYear(),
        month = date.getMonth() + 1,
        day = date.getDate();
    return Date.parse(year + '-' + month + '-' + day) ;
}

原来当年月日中间用’-‘的符号的时候,它的解析是用UTC 时区处理,而不是用本地时区处理的,因此和格林尼治恰好差8小时,就成了这个时间点到1970年1月1日08:00的毫秒数。
解决的方法是中间用其他符号,如‘/’。
然后getTime()也会有一样的问题。

function formatDate(isoDateString) { const date = new Date(isoDateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始 const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } Page({ data: { inventoryList: [], // 原始已盘点物料列表 filteredList: [], // 筛选后的列表(用于展示) categories: ['全部分类'], // 物料分类列表(下拉选项,默认包含“全部分类”) selectedCategoryIndex: 0, // 选中的分类索引(默认选中“全部分类”) nameKeyword: '', // 物料名称关键词 isLoading: false, // 加载状态 isExporting: false, //导出加载状态 emptyTip: '暂无盘点记录' // 空状态提示 }, /** * 格式化时间 */ /** * 页面加载时获取数据 */ onLoad() { wx.setNavigationBarTitle({ title: '盘点结果' // 这里的标题会显示在顶部导航栏 }); this.getInventoryResult(); // 先获取已盘点物料 }, /** * 获取已盘点物料 + 提取分类列表 */ async getInventoryResult() { this.setData({ isLoading: true }); try { // 1. 查询所有已盘点物料 const result = await wx.cloud.database() .collection('materials') .where({ isInventoried: true }) .orderBy('inventoryTime', 'desc') .get(); const inventoryList = result.data.map(item => ({ ...item, inventoryTime: item.inventoryTime ?? '未记录' })); // 2. 提取所有不重复的物料分类(用于下拉框) const categorySet = new Set(); inventoryList.forEach(item => { if (item.materialCategory) { categorySet.add(item.materialCategory); } }); // 合并“全部分类”实际分类(去重) const categories = ['全部分类', ...Array.from(categorySet)]; this.setData({ inventoryList, filteredList: inventoryList, // 初始展示全部 categories, emptyTip: inventoryList.length === 0 ? '暂无盘点记录' : '筛选无结果', isLoading: false }); } catch (err) { console.error('获取数据失败', err); wx.showToast({ title: '加载失败,请重试', icon: 'none' }); this.setData({ isLoading: false }); } }, /** * 处理分类下拉选择变化 */ handleCategoryChange(e) { this.setData({ selectedCategoryIndex: e.detail.value }); }, /** * 处理物料名称输入 */ handleNameInput(e) { this.setData({ nameKeyword: e.detail.value.trim() }); }, /** * 执行筛选逻辑 */ handleFilter() { const { inventoryList, categories, selectedCategoryIndex, nameKeyword } = this.data; const selectedCategory = categories[selectedCategoryIndex]; // 选中的分类名称 // 筛选规则: const filtered = inventoryList.filter(item => { // 1. 分类筛选(“全部分类”则不过滤) const matchCategory = selectedCategory === '全部分类' ? true : item.materialCategory === selectedCategory; // 2. 名称模糊筛选(空关键词则不过滤) const matchName = !nameKeyword ? true : (item.materialName || '').toLowerCase().includes(nameKeyword.toLowerCase()); return matchCategory && matchName; // 同时满足两个条件 }); this.setData({ filteredList: filtered, emptyTip: filtered.length === 0 ? '筛选无结果' : '暂无盘点记录' }); }, async handleExportExcel() { const { filteredList } = this.data; // 验证数据 if (filteredList.length === 0) { wx.showToast({ title: '没有可导出的数据', icon: 'none' }); return; } this.setData({ isExporting: true }); try { // 调用云函数导出Excel const res = await wx.cloud.callFunction({ name: 'exportExcel', data: { data: filteredList } // 传递筛选后的数据 }); const { success, fileID, errMsg } = res.result; if (success && fileID) { // 下载Excel文件 const downloadRes = await wx.cloud.downloadFile({ fileID: fileID }); // 保存文件到本地 const saveRes = await wx.saveFile({ tempFilePath: downloadRes.tempFilePath }); wx.showToast({ title: '导出成功', icon: 'success' }); // 提示用户文件保存路径 wx.showModal({ title: '导出成功', content: `文件已保存至:${saveRes.savedFilePath}`, showCancel: false }); } else { wx.showToast({ title: errMsg || '导出失败', icon: 'none' }); } } catch (err) { console.error('导出Excel失败', err); wx.showToast({ title: '导出失败,请重试', icon: 'none' }); } finally { this.setData({ isExporting: false }); } }, /** * 重置筛选条件 */ handleReset() { this.setData({ selectedCategoryIndex: 0, // 重置为“全部分类” nameKeyword: '', // 清空名称关键词 filteredList: this.data.inventoryList, // 恢复展示全部 emptyTip: this.data.inventoryList.length === 0 ? '暂无盘点记录' : '筛选无结果' }); }, /** * 格式化时间 */ formatTime(isoTime) { if (!isoTime) return '未记录'; const date = new Date(isoTime); return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; }, /** * 返回上一页 */ navigateBack() { wx.navigateBack(); } }) <view class="container"> <!-- 筛选区域 --> <view class="filter-bar"> <view class="filter-item"> <text class="filter-label">物料分类:</text> <picker class="picker" value="{{selectedCategoryIndex}}" range="{{categories}}" bindchange="handleCategoryChange" > <view class="picker-view">{{categories[selectedCategoryIndex]}}</view> </picker> </view> <view class="filter-item"> <text class="filter-label">物料名称:</text> <input class="name-input" placeholder="请输入名称关键词" bindinput="handleNameInput" value="{{nameKeyword}}" /> </view> <view class="filter-btns"> <button class="filter-btn" bindtap="handleFilter">筛选</button> <button class="reset-btn" bindtap="handleReset">重置</button> </view> </view> <!-- 加载状态列表 --> <view wx:if="{{isLoading}}" class="loading">加载中...</view> <view class="result-list" wx:else> <block wx:for="{{filteredList}}" wx:key="materialCode"> <view class="item"> <view class="item-info"> <view class="item-name">{{item.materialName}}</view> <view class="item-desc"> {{item.materialCode}} | {{item.materialCategory || '无'}} | {{item.specification}} </view> <view class="item-meta"> <text>盘点数量:{{item.inventoryCount}}</text> <text>盘点时间:{{formatDate(item.inventoryTime)}}</text> <text>原始时间:{{item.inventoryTime}}</text> </view> </view> </view> </block> <view wx:if="{{filteredList.length === 0 && !isLoading}}" class="empty-tip"> {{emptyTip}} </view> </view> <!-- 底部固定按钮组 --> <view class="bottom-btn-group"> <button class="export-btn" bindtap="handleExportExcel" loading="{{isExporting}}"> 导出Excel </button> <button class="back-btn" bindtap="navigateBack"> 返回 </button> </view> </view> 请帮我修改,盘点时间不显示
08-10
computed: { // 从localstorage中获取userId userId() { return localStorage.getItem("userId") == 1; }, deviceArray() { // 确保当onLineDeviceMap为null或undefined时,我们使用空数组 const values = pageModel.pageInfo.onLineDeviceMap?.values(); // 如果values是undefined,则返回空数组,否则将可迭代对象转为数组 return Array.from(values || []); } }, watch: { osdUavHome(newVal, oldVal) { if (newVal === null && this.currentUavHome) { //如果osd没有数据,则机巢不在线,需刷新 // this.$refs.mineMapRef.showUav(); this.currentUavHome = null; } if (newVal && this.currentUavHome) { // this.$refs.mineMapRef.delPopup(); //检测到osd有数据显示机巢的信息 this.$message.success("机巢数据加载成功"); // this.showUavHomeMessage({ isMqtt: true }); } }, deviceArray: { deep: true, // 关键:启用深度监听 immediate: true, handler(newVal) { this.updateDeviceArray(newVal) console.log('计算属性变化已捕获', newVal) } }, }, created() { InitPageData.init(this); }, mounted() { this.handleTestTime(); // this.showUavInit(); }, methods: { updateDeviceArray(devices) { this.deviceArray.push(devices) console.log(this.deviceArray, '将Map的值转换为数组'); // 注意:这里我们只处理了整个Map被替换的情况,但Map内部变化不会触发 },pageModel.pageInfo.oneVideoCvNetMqttObj.on('message', (topic, message) => { const res = JSON.parse(message.toString()) // res.time = new Date().getTime() console.log("收到特勤路线【车载】。。。。。。。。。。", res) // 假设消息格式为:{ deviceId: '设备ID', longitude: 经度, latitude: 纬度 } const { deviceId, longitude, latitude, speedKph } = res; // console.log("mqtt消息:", res); pageModel.pageInfo.onLineDeviceMap.set(res.deviceId,res); // console.log("mqtt消息:pageModel.pageInfo.onLineDeviceMap", pageModel.pageInfo.onLineDeviceMap); }) /**在线设备map*/ onLineDeviceMap: Map<any, any> = new Map();没有执行打印 console.log(this.deviceArray, '将Map的值转换为数组');
07-26
<think>我们正在讨论如何使用JavaScriptDate.parse方法将字符串转换为日期对象。根据引用[2],Date.parse()函数用于解析一个日期字符串,并返回该日期与1970年1月1日午夜(UTC)之间相差的毫秒数。但是,我们通常需要的是一个日期对象,而不是毫秒数。因此,我们可以将Date.parse()的结果传递给Date构造函数来创建一个日期对象。注意:Date.parse()的输入字符串格式是重要的。它支持多种格式,但不同浏览器可能对非标准格式的支持不同。引用[3]展示了一个自定义函数来解析特定格式的字符串(如"2017-02-16"、"2017/02/16"、"2017.02.16")并创建日期对象。然而,我们也可以直接使用Date.parse()然后构造Date对象,或者直接使用newDate(string)来创建日期对象。另外,引用[4]提到在JSON.parse时使用reviver函数将日期字符串转换为Date对象,这也是一种常见的做法。因此,我们可以通过以下方式将字符串转换为日期对象:1.使用Date.parse()获取毫秒数,然后创建Date对象:letmilliseconds=Date.parse(dateString);letdateObj=newDate(milliseconds);2.直接使用newDate()构造函数,传入字符串:letdateObj=newDate(dateString);但是,需要注意的是,Date.parse()对于某些格式可能返回NaN(如果无法解析),所以我们需要检查返回值。此外,引用[3]还提到,使用自定义分割函数可以避免一些时区问题(比如解析后的小时是8点,可能是因为时区问题,比如UTC+8)。所以,有时候我们可能需要手动解析字符串来避免时区问题。下面我们提供两种主要方法,并讨论它们的注意事项。方法一:使用Date.parse()Date构造函数步骤:a.使用Date.parse(dateString)解析字符串,得到毫秒数。b.如果返回的是NaN,则表示字符串无法解析。c.否则,用这个毫秒数创建Date对象。方法二:直接使用newDate(dateString)letdateObj=newDate(dateString);如果dateString无效,则dateObj会是InvalidDate,我们可以通过isNaN(dateObj.getTime())来检查。但是,这两种方法都可能受到时区的影响。例如,如果字符串是"2021-01-01",那么它会被解析为UTC时间,而用newDate()创建时,在本地时区显示的时间可能会有所不同。为了避免时区问题,我们可以使用引用[3]中的方法,手动分割字符串,然后使用newDate(year,monthIndex,day)的方式,注意monthIndex是从0开始的(0代表1月)。因此,我们也可以提供第三种方法:手动解析字符串(尤其是当字符串格式固定且简单时)。根据用户提供的引用[3]中的函数,我们可以这样写:```javascriptfunctionparseDate(dateString){//支持的分隔符:-/.constseparators=['-','/','.'];letfoundSeparator=separators.find(sep=>dateString.includes(sep));if(!foundSeparator){//如果没有找到分隔符,尝试其他方法或报错returnnewDate(NaN);}letparts=dateString.split(foundSeparator);//注意:parts[0]是年,parts[1]是月(0-11),parts[2]是日//月份需要减1,因为JavaScript中月份从0开始returnnewDate(parts[0],parts[1]-1,parts[2]);}```但是,这种方法没有处理时间部分,只处理了日期部分。如果字符串包含时间,我们需要额外处理。因此,我们根据需求选择方法。总结:1.如果字符串是ISO8601格式(如"2017-11-30T12:00:00.000Z"),那么使用Date.parse或newDate()都能正确解析,且时区为UTC(带Z表示UTC)。2.如果字符串是其他格式,且不包含时区信息,则解析结果会基于本地时区。3.如果我们需要精确控制,建议手动解析字符串并分别指定年、月、日、时、分、秒等。下面我们给出一个示例,展示如何将Date.parse解析的字符串转换为日期对象:```javascript//方法1:使用Date.parseDate构造函数constdateString="2021-01-01T00:00:00.000Z";//ISO格式constmilliseconds=Date.parse(dateString);if(isNaN(milliseconds)){console.log("日期字符串解析失败");}else{constdateObj=newDate(milliseconds);console.log(dateObj);//输出:2021-01-01T00:00:00.000Z(在控制台显示为本地时间)}//方法2:直接使用newDateconstdateObj2=newDate(dateString);if(isNaN(dateObj2.getTime())){console.log("日期字符串解析失败");}else{console.log(dateObj2);}//方法3:手动解析(仅日期部分,无时间)functionparseDateString(dateStr){constseparators=['-','/','.'];letseparator=separators.find(sep=>dateStr.includes(sep));if(!separator)returnnewDate(NaN);let[year,month,day]=dateStr.split(separator).map(Number);returnnewDate(year,month-1,day);}constdateObj3=parseDateString("2021.05.15");console.log(dateObj3);//注意:这里创建的是本地时区的日期对象,时间部分为00:00:00(本地时间)```注意:方法3创建的是本地时区的日期对象,没有时间部分(默认为00:00:00本地时间),也没有时区转换。根据需求选择合适的方法。如果字符串包含时间且格式复杂,建议使用成熟的日期库(如moment.jsdate-fns)。最后,如果从JSON中解析日期字符串,可以使用JSON.parse的reviver函数,如引用[4]所示。</think>### JavaScript 中使用 `Date.parse()` 将字符串转换为日期格式详解 #### 1. `Date.parse()` 的基本用法 `Date.parse()` 方法用于解析日期字符串,返回 **自 1970-1-1 00:00:00 UTC 起的毫秒数**(时间戳)[^1][^2]。这是将字符串转换为日期的基础步骤: ```javascript const timestamp = Date.parse("2023-08-15T14:30:00"); console.log(timestamp); // 输出:1692102600000(毫秒级时间戳) ``` #### 2. 将时间戳转换为日期对象 获得时间戳后,通过 `new Date()` 构造函数即可转换为标准日期对象: ```javascript const dateString = "2023-08-15"; const timestamp = Date.parse(dateString); const dateObj = new Date(timestamp); console.log(dateObj); // 输出:Tue Aug 15 2023 08:00:00 GMT+0800 (中国标准时间) console.log(dateObj.getFullYear()); // 2023 console.log(dateObj.getMonth() + 1); // 8(月份从0开始) console.log(dateObj.getDate()); // 15 ``` > **注意时区问题**: > 如果字符串不包含时区信息(如 `"2023-08-15"`),解析结果会基于**本地时区**(上例中的 GMT+8)[^3]。 #### 3. 直接使用 `new Date()` 简化操作 实际上,直接将字符串传入 `new Date()` 构造函数会自动调用 `Date.parse()`: ```javascript // 等效于 Date.parse() + new Date() const dateObj = new Date("2023-08-15T14:30:00"); ``` #### 4. 处理特殊格式的日期字符串 对于非标准格式(如 `"2023.08.15"`),可手动分割后构建日期对象[^3]: ```javascript function parseCustomDate(str) { const separators = ["-", "/", "."]; const separator = separators.find(s => str.includes(s)); const [year, month, day] = str.split(separator).map(Number); return new Date(year, month - 1, day); // 月份需减1 } const date = parseCustomDate("2023.08.15"); console.log(date); // 2023-08-15T00:00:00.000Z ``` #### 5. 处理 JSON 中的日期字符串 解析 JSON 数据时,可通过 **reviver 函数**自动转换日期字段[^4]: ```javascript const jsonStr = '{"event":"会议","date":"2023-08-15T14:30:00.000Z"}'; const data = JSON.parse(jsonStr, (key, value) => { if (key === "date") return new Date(value); return value; }); console.log(data.date instanceof Date); // true console.log(data.date.getHours()); // 14(UTC时间) ``` #### 6. 注意事项 1. **格式兼容性** 支持 ISO 8601 格式(`YYYY-MM-DDTHH:mm:ss.sssZ`),其他格式可能因浏览器而异[^1][^2]。 2. **无效日期处理** 解析失败时返回 `NaN`: ```javascript const invalid = Date.parse("无效日期"); console.log(isNaN(invalid)); // true ``` 3. **时区明确性** - 带 `Z` 的字符串(如 `2023-08-15T14:30:00Z`)表示 UTC 时间 - 无时区标识的字符串按本地时区解析 --- ### 常见日期字符串格式示例 | 格式 | 示例 | 说明 | |------|------|------| | ISO 8601 | `"2023-08-15T14:30:00Z"` | UTC 时间 | | 简化格式 | `"2023-08-15"` | 本地时区午夜 | | 带时区 | `"Aug 15, 2023 14:30:00 GMT+0800"` | 指定时区 | | 自定义 | `"2023/08/15"` | 需手动处理[^3] | > 建议优先使用 ISO 8601 格式保证跨平台一致性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值