|
|
@@ -0,0 +1,146 @@
|
|
|
+"use strict";
|
|
|
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
|
+ if (k2 === undefined) k2 = k;
|
|
|
+ var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
+ desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
+ }
|
|
|
+ Object.defineProperty(o, k2, desc);
|
|
|
+}) : (function(o, m, k, k2) {
|
|
|
+ if (k2 === undefined) k2 = k;
|
|
|
+ o[k2] = m[k];
|
|
|
+}));
|
|
|
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
|
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
|
+}) : function(o, v) {
|
|
|
+ o["default"] = v;
|
|
|
+});
|
|
|
+var __importStar = (this && this.__importStar) || (function () {
|
|
|
+ var ownKeys = function(o) {
|
|
|
+ ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
|
+ var ar = [];
|
|
|
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
|
+ return ar;
|
|
|
+ };
|
|
|
+ return ownKeys(o);
|
|
|
+ };
|
|
|
+ return function (mod) {
|
|
|
+ if (mod && mod.__esModule) return mod;
|
|
|
+ var result = {};
|
|
|
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
|
+ __setModuleDefault(result, mod);
|
|
|
+ return result;
|
|
|
+ };
|
|
|
+})();
|
|
|
+Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
+exports.TimezoneService = void 0;
|
|
|
+const luxon_1 = require("luxon");
|
|
|
+const ct = __importStar(require("countries-and-timezones"));
|
|
|
+// 自定义默认时区映射表
|
|
|
+const defaultTimezoneMap = {
|
|
|
+ BR: "America/Sao_Paulo", // 巴西(圣保罗)
|
|
|
+ RU: "Europe/Moscow", // 俄罗斯(莫斯科)
|
|
|
+ US: "America/New_York", // 美国(纽约,代表东部时区)
|
|
|
+ IN: "Asia/Kolkata", // 印度(加尔各答)
|
|
|
+ MX: "America/Mexico_City", // 墨西哥(墨西哥城)
|
|
|
+ AR: "America/Argentina/Buenos_Aires", // 阿根廷(布宜诺斯艾利斯)
|
|
|
+ ID: "Asia/Jakarta", // 印尼(雅加达)
|
|
|
+ ES: "Europe/Madrid", // 西班牙(马德里)
|
|
|
+ CL: "America/Santiago", // 智利(圣地亚哥)
|
|
|
+ CO: "America/Bogota", // 哥伦比亚(波哥大)
|
|
|
+ FR: "Europe/Paris", // 法国(巴黎)
|
|
|
+ IT: "Europe/Rome", // 意大利(罗马)
|
|
|
+ PL: "Europe/Warsaw", // 波兰(华沙)
|
|
|
+ DE: "Europe/Berlin", // 德国(柏林)
|
|
|
+ RO: "Europe/Bucharest", // 罗马尼亚(布加勒斯特)
|
|
|
+ GB: "Europe/London", // 英国(伦敦)
|
|
|
+ UA: "Europe/Kyiv", // 乌克兰(基辅)
|
|
|
+ TR: "Europe/Istanbul", // 土耳其(伊斯坦布尔)
|
|
|
+ JP: "Asia/Tokyo", // 日本(东京)
|
|
|
+ PH: "Asia/Manila", // 菲律宾(马尼拉)
|
|
|
+ KR: "Asia/Seoul", // 韩国(首尔)
|
|
|
+ CA: "America/Toronto", // 加拿大(多伦多,代表东部时区)
|
|
|
+ IR: "Asia/Tehran", // 伊朗(德黑兰)
|
|
|
+ TH: "Asia/Bangkok", // 泰国(曼谷)
|
|
|
+ CR: "America/Costa_Rica", // 哥斯达黎加(圣何塞)
|
|
|
+ ZA: "Africa/Johannesburg", // 南非(约翰内斯堡)
|
|
|
+ VE: "America/Caracas", // 委内瑞拉(加拉加斯)
|
|
|
+ AU: "Australia/Sydney", // 澳大利亚(悉尼,代表东部时区)
|
|
|
+ PK: "Asia/Karachi", // 巴基斯坦(卡拉奇)
|
|
|
+ VN: "Asia/Ho_Chi_Minh", // 越南(胡志明市)
|
|
|
+ HU: "Europe/Budapest", // 匈牙利(布达佩斯)
|
|
|
+ PT: "Europe/Lisbon", // 葡萄牙(里斯本)
|
|
|
+ EG: "Africa/Cairo", // 埃及(开罗)
|
|
|
+ CN: "Asia/Shanghai", // 中国(上海)
|
|
|
+};
|
|
|
+/**
|
|
|
+ * 这是一个处理时区转换的单例服务。
|
|
|
+ */
|
|
|
+class TimezoneService {
|
|
|
+ constructor() { }
|
|
|
+ static getInstance() {
|
|
|
+ if (!TimezoneService.instance) {
|
|
|
+ TimezoneService.instance = new TimezoneService();
|
|
|
+ }
|
|
|
+ return TimezoneService.instance;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 根据国家代码获取对应的时区。
|
|
|
+ * 优先从自定义映射表中查找,如果找不到,则退回到 countries-and-timezones 库的第一个时区。
|
|
|
+ * 如果仍找不到,默认返回 'UTC'。
|
|
|
+ * @param countryCode 国家代码(如 'US', 'CN')
|
|
|
+ * @returns 时区字符串(如 'Asia/Shanghai')
|
|
|
+ */
|
|
|
+ getTimezoneByCountryCode(countryCode) {
|
|
|
+ const uppercaseCc = countryCode.toUpperCase();
|
|
|
+ // 1. 优先从自定义映射表中查找
|
|
|
+ if (defaultTimezoneMap[uppercaseCc]) {
|
|
|
+ return defaultTimezoneMap[uppercaseCc];
|
|
|
+ }
|
|
|
+ // 2. 如果自定义映射表中没有,则退回到 countries-and-timezones 库
|
|
|
+ const country = ct.getCountry(uppercaseCc);
|
|
|
+ if (country && country.timezones && country.timezones.length > 0) {
|
|
|
+ return country.timezones[0];
|
|
|
+ }
|
|
|
+ // 3. 最终默认值
|
|
|
+ return "UTC";
|
|
|
+ }
|
|
|
+ getNowInTimezone(timezone) {
|
|
|
+ return luxon_1.DateTime.now().setZone(timezone);
|
|
|
+ }
|
|
|
+ getUTCFromTimezoneDate(localDateTime, timezone) {
|
|
|
+ const zonedTime = localDateTime.setZone(timezone, { keepLocalTime: true });
|
|
|
+ return zonedTime.toJSDate();
|
|
|
+ }
|
|
|
+ getPlannedSendTime(cc, targetHour) {
|
|
|
+ const now = luxon_1.DateTime.now().toUTC();
|
|
|
+ const timezone = this.getTimezoneByCountryCode(cc || "US");
|
|
|
+ const plannedTime = now.setZone(timezone).set({ hour: targetHour, minute: 0, second: 0, millisecond: 0 });
|
|
|
+ let plannedSendAt = plannedTime.toUTC();
|
|
|
+ if (plannedSendAt < now) {
|
|
|
+ plannedSendAt = plannedSendAt.plus({ days: 1 });
|
|
|
+ }
|
|
|
+ return plannedSendAt.toJSDate();
|
|
|
+ }
|
|
|
+}
|
|
|
+exports.TimezoneService = TimezoneService;
|
|
|
+// ---
|
|
|
+// 示例用法(非代码库一部分,仅供测试)
|
|
|
+if (require.main === module) {
|
|
|
+ const timezoneService = TimezoneService.getInstance();
|
|
|
+ const userCountryCode = "RU";
|
|
|
+ const targetHour = 8; // 巴西当地早上8点
|
|
|
+ // 验证 getPlannedSendTime 方法
|
|
|
+ const plannedTimeUTC = timezoneService.getPlannedSendTime(userCountryCode, targetHour);
|
|
|
+ const plannedTimeUTCISO = plannedTimeUTC.toISOString();
|
|
|
+ // 获取北京时间,用于对比
|
|
|
+ const beijingTimezone = timezoneService.getTimezoneByCountryCode("CN");
|
|
|
+ const beijingTime = luxon_1.DateTime.fromJSDate(plannedTimeUTC, { zone: beijingTimezone });
|
|
|
+ console.log(`--- 计算结果 ---`);
|
|
|
+ console.log(`用户国家:${userCountryCode}`);
|
|
|
+ console.log(`目标时区:${timezoneService.getTimezoneByCountryCode(userCountryCode)}`);
|
|
|
+ console.log(`目标当地时间:${targetHour}:00:00`);
|
|
|
+ console.log(`计算出的UTC计划发送时间:${plannedTimeUTCISO}`);
|
|
|
+ console.log(`对应的北京时间:${beijingTime.toLocaleString(luxon_1.DateTime.DATETIME_FULL)}`);
|
|
|
+ console.log(`对应的北京时间(ISO):${beijingTime.toISO()}`);
|
|
|
+}
|