Ionic 3:获取特定国家谷歌服务器当前时间及Firebase上传需求
嗨,针对你在Ionic 3开发中遇到的「上传位置到Firebase时不用本地时间、改用可信的谷歌服务器时间,同时获取特定国家当前时间」的需求,我给你整理了几个实用的解决方案,都是贴合谷歌生态的靠谱做法:
Firebase本身就提供了服务器时间戳功能,这个时间是直接从Firebase(谷歌)服务器生成的,完全不受用户本地设备时间篡改的影响,是最可靠的选择。
1. 把时间戳集成到你的上传函数里
假设你原来的上传函数大概是这样的:
// 你原来的上传位置函数 uploadUserLocation(lat: number, lng: number) { const locationRef = firebase.database().ref('user_locations'); locationRef.push({ latitude: lat, longitude: lng // 之前没加时间字段 }); }
现在修改成带服务器时间戳的版本:
// 记得先导入firebase import * as firebase from 'firebase'; uploadUserLocation(lat: number, lng: number) { const locationRef = firebase.database().ref('user_locations'); locationRef.push({ latitude: lat, longitude: lng, // 新增服务器时间戳字段 timestamp: firebase.database.ServerValue.TIMESTAMP }); }
这个TIMESTAMP会在数据写入Firebase的瞬间,自动替换成谷歌服务器的UTC时间戳(毫秒数),绝对可信,完全不用担心本地时间被篡改的问题。
2. 把UTC时间转成特定国家的本地时间
如果需要展示特定国家/地区的时间(比如中国上海、美国纽约),可以在从Firebase拿到数据后,用时区工具转换:
- 先安装兼容Ionic 3的
moment-timezone库:
npm install moment moment-timezone --save
- 然后在代码里做转换:
import * as moment from 'moment-timezone'; // 假设从Firebase快照里拿到了timestamp值 const serverTimestamp = snapshot.val().timestamp; // 转成中国上海时间(时区标识是Asia/Shanghai) const shanghaiTime = moment(serverTimestamp).tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss'); // 转成美国纽约时间(时区标识是America/New_York) const nyTime = moment(serverTimestamp).tz('America/New_York').format('YYYY-MM-DD HH:mm:ss');
这里的时区标识用的是IANA标准,每个国家/地区对应唯一的标识,能自动处理夏令时这类时间偏移变化,比直接用UTC+8这种硬编码靠谱多了。
如果你一定要直接从谷歌服务器拿到特定国家的当前时间(而不是先存UTC再转换),可以用Google Time Zone API:
1. 先准备API密钥
你需要去Google Cloud控制台创建一个API密钥,然后启用「Time Zone API」服务。
2. 在Ionic里发起请求获取时间
用Ionic的HttpClient来请求API,甚至可以直接用用户上传的位置经纬度来对应时区:
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { map } from 'rxjs/operators'; @Injectable() export class TimeService { constructor(private http: HttpClient) {} getSpecificCountryTime(lat: number, lng: number) { const apiKey = '你的Google API密钥'; // 这里用Date.now()只是给API传一个参考时间戳,实际时间由API返回的时区偏移计算 const utcTimestamp = Date.now() / 1000; const apiUrl = `https://maps.googleapis.com/maps/api/timezone/json?location=${lat},${lng}×tamp=${utcTimestamp}&key=${apiKey}`; return this.http.get(apiUrl).pipe( map(response => { // 解析API返回的时区偏移和夏令时偏移 const dstOffset = response['dstOffset']; const rawOffset = response['rawOffset']; // 计算目标时区的当前时间戳(毫秒) const targetTimestamp = Date.now() + (dstOffset + rawOffset) * 1000; return new Date(targetTimestamp); }) ); } }
然后在你的上传函数里调用这个服务,把拿到的特定国家时间一起上传:
uploadUserLocation(lat: number, lng: number) { this.timeService.getSpecificCountryTime(lat, lng).subscribe(targetDate => { const locationRef = firebase.database().ref('user_locations'); locationRef.push({ latitude: lat, longitude: lng, countrySpecificTime: targetDate.toISOString() }); }); }
不过要注意,这种方式需要额外的API请求,依赖网络状态,而且还要管理API密钥的权限,所以还是优先推荐第一种Firebase内置的方案。
- 绝对不要用
new Date()或者Date.now()直接上传时间!用户完全可以修改设备本地时间,导致你的时间数据完全不可信。 - 如果你用的是Firestore而不是实时数据库,服务器时间戳的用法是
firebase.firestore.FieldValue.serverTimestamp(),逻辑是一样的。 - 时区标识一定要用IANA标准的(比如
Asia/Tokyo),别用UTC+9这种硬编码,不然夏令时切换的时候时间会出错。
内容的提问来源于stack exchange,提问作者Semah

