逻辑时间工具库
概述
这是一个基于 GS 语言的逻辑时间工具库,用于管理和操作服务器的逻辑时间,区别于系统原生的基于真实时间的接口。该工具库提供了丰富的时间管理、计算和事件通知功能,为游戏服务器提供统一的时间服务。
主要特性
逻辑时间管理
- 获取和维护服务器的逻辑时间(
now
) - 支持设置时区(
set_time_zone
,get_time_zone
) - 支持设置时间偏移量(
set_time_offset
,get_time_offset
) - 支持暂停和恢复时间流动(
pause_time
,resume_time
) - 支持偏移时间持久化和进程间同步
- 临时将持久化数据保存在本地文件中:
/pkg/logical_time/logical_time_d.o
- 临时将持久化数据保存在本地文件中:
常用时间函数
- 时间格式化和解析(
format_local_time
,parse_local_time
) - 时间比较(同一分、同一小时、同一天、同一周、同一月、同一年)
- 计算两个时间累计经过多少天
- 计算指定时间是今年、今月、今周、今天、当前小时的开始和结束时间
- 闰年计算相关
- 友好时间文本展示
- 不处理夏令时相关逻辑
事件通知机制
- 时间服务就绪事件
- 时间流动暂停事件
- 时间流动恢复事件
- 时间偏移量变更事件
每日重置偏移时间管理(Daily Reset Offset)
逻辑时间库支持设置每日重置偏移时间,用于定义游戏的"一天"开始时间。这个功能对于需要在非午夜时间点进行每日重置的游戏特别有用。
函数原型 | 函数作用 |
---|---|
int get_daily_reset_offset_time() | 获取每日重置偏移时间(秒) |
int get_daily_reset_offset_hours() | 获取每日重置偏移时间(小时) |
每日重置周期计算(Daily Reset Cycle)
基于设置的每日重置偏移时间,提供一系列计算和判断函数:
函数原型 | 函数作用 |
---|---|
int get_previous_reset_day_start(int timestamp = 0) | 获取前一个重置天的开始时间 |
int get_previous_reset_day_end(int timestamp = 0) | 获取前一个重置天的结束时间 |
int get_reset_day_start(int timestamp = 0) | 获取指定时间所在天的重置开始时间 |
int get_reset_day_end(int timestamp = 0) | 获取指定时间所在天的重置结束时间 |
int get_next_reset_day_start(int timestamp = 0) | 获取下一个重置天的开始时间 |
int get_next_reset_day_end(int timestamp = 0) | 获取下一个重置天的结束时间 |
bool is_same_reset_day(int time1, int time2) | 判断两个时间是否在同一个重置周期内 |
bool is_today_reset_cycle(int timestamp) | 判断指定时间是否在今天的重置周期内 |
bool is_yesterday_reset_cycle(int timestamp) | 判断指定时间是否在昨天的重置周期内 |
int between_reset_days(int time1, int time2) | 计算两个时间之间相差多少个重置天数 |
int get_previous_reset_week_start(int timestamp = 0) | 获取前一个重置周的开始时间 |
int get_previous_reset_week_end(int timestamp = 0) | 获取前一个重置周的结束时间 |
int get_reset_week_start(int timestamp = 0) | 获取指定时间所在周的重置开始时间(周一的重置时间) |
int get_reset_week_end(int timestamp = 0) | 获取指定时间所在周的重置结束时间(周日的重置结束时间) |
int get_next_reset_week_start(int timestamp = 0) | 获取下一个重置周的开始时间 |
int get_next_reset_week_end(int timestamp = 0) | 获取下一个重置周的结束时间 |
int get_previous_reset_month_start(int timestamp = 0) | 获取前一个重置月的开始时间 |
int get_previous_reset_month_end(int timestamp = 0) | 获取前一个重置月的结束时间 |
int get_reset_month_start(int timestamp = 0) | 获取指定时间所在月的重置开始时间(1号的重置时间) |
int get_reset_month_end(int timestamp = 0) | 获取指定时间所在月的重置结束时间(月末的重置结束时间) |
int get_next_reset_month_start(int timestamp = 0) | 获取下一个重置月的开始时间 |
int get_next_reset_month_end(int timestamp = 0) | 获取下一个重置月的结束时间 |
int get_previous_reset_year_start(int timestamp = 0) | 获取前一个重置年的开始时间 |
int get_previous_reset_year_end(int timestamp = 0) | 获取前一个重置年的结束时间 |
int get_reset_year_start(int timestamp = 0) | 获取指定时间所在年的重置开始时间(1月1号的重置时间) |
int get_reset_year_end(int timestamp = 0) | 获取指定时间所在年的重置结束时间(12月31号的重置结束时间) |
int get_next_reset_year_start(int timestamp = 0) | 获取下一个重置年的开始时间 |
int get_next_reset_year_end(int timestamp = 0) | 获取下一个重置年的结束时间 |
文件结构
logical_time.gs
- 对外接口封装,绝大部分接口都以逻辑时间戳为基础LogicalTimeD.gs
- 逻辑时间管理守护进程,提供逻辑时间的偏移量及时区管理,以及简单的内部事件注册回调支持date_formatter.gs
- 时间格式化和解析工具类,提供时间格式化和解析的功能,可用于真实时间的工具类函数集合
组件接口
logical_time.gs
函数原型 | 函数作用 |
---|---|
int now() | 获取当前逻辑时间戳 |
bool set_time_zone(int time_zone) | 设置时区(-12~14) |
int get_time_zone() | 获取当前时区 |
bool set_time_offset(int offset) | 设置时间偏移量(秒) |
int get_time_offset() | 获取时间偏移量 |
bool pause_time() | 暂停时间流动 |
bool resume_time() | 恢复时间流动 |
bool is_time_paused() | 判断时间是否暂停 |
int add_time(int timestamp, int years = 0, int months = 0, int days = 0, int hours = 0, int minutes = 0, int seconds = 0) | 向指定时间戳添加时间 |
int add_years(int timestamp, int years) | 增加年份 |
int add_months(int timestamp, int months) | 增加月份 |
int add_days(int timestamp, int days) | 增加天数 |
int add_hours(int timestamp, int hours) | 增加小时 |
int add_minutes(int timestamp, int minutes) | 增加分钟 |
int add_seconds(int timestamp, int seconds) | 增加秒数 |
bool is_same_year(int time1, int time2) | 判断两个时间是否在同一年 |
bool is_same_month(int time1, int time2) | 判断两个时间是否在同一月 |
bool is_same_day(int time1, int time2) | 判断两个时间是否在同一天 |
bool is_same_hour(int time1, int time2) | 判断两个时间是否在同一小时 |
bool is_same_minute(int time1, int time2) | 判断两个时间是否在同一分钟 |
int get_hour_start(int timestamp) | 获取指定时间所在小时的开始时间 |
int get_hour_end(int timestamp) | 获取指定时间所在小时的结束时间 |
int get_day_start(int timestamp) | 获取指定时间所在天的开始时间 |
int get_day_end(int timestamp) | 获取指定时间所在天的结束时间 |
int get_week_start(int timestamp) | 获取指定时间所在周的开始时间 |
int get_week_end(int timestamp) | 获取指定时间所在周的结束时间 |
int get_month_start(int timestamp) | 获取指定时间所在月的开始时间 |
int get_month_end(int timestamp) | 获取指定时间所在月的结束时间 |
int get_year_start(int timestamp) | 获取指定时间所在年的开始时间 |
int get_year_end(int timestamp) | 获取指定时间所在年的结束时间 |
string format_local_time(string format, int timestamp = 0) | 格式化本地时间 |
int parse_local_time(string format, string date_str) | 解析本地时间字符串 |
int between_days(int time1, int time2) | 计算两个时间戳之间相差的天数,返回正数表示 time2 在 time1 之后,负数表示 time2 在 time1 之前 |
bool is_leap_year(int year) | 判断是否为闰年年份 |
样例
基本时间操作
import pkg.logical_time;
// 获取当前时间戳
int now = logical_time.now();
// 获取当前时间戳(最简写法)
int now = now();
// 设置时区为东八区
set_time_zone(8);
// 设置时间偏移(提前1小时)
set_time_offset(3600);
// 暂停时间
pause_time();
// 恢复时间
resume_time();
时间计算
// 获取当前时间
int now = logical_time.now();
// 计算1年2个月3天4小时5分钟6秒后的时间
int future = logical_time.add_time(now, 1, 2, 3, 4, 5, 6);
// 计算昨天同一时间
int yesterday = logical_time.add_days(now, -1);
// 计算下个月初
int next_month_start = logical_time.get_month_start(logical_time.add_months(now, 1));
时间比较
// 判断两个时间是否在同一天
int time1 = logical_time.parse_local_time("%Y-%m-%d %H:%M:%S", "2025-03-27 10:00:00");
int time2 = logical_time.parse_local_time("%Y-%m-%d %H:%M:%S", "2025-03-27 15:30:00");
bool same_day = logical_time.is_same_day(time1, time2); // true
// 判断是否今天
bool is_today = logical_time.is_same_day(time1, logical_time.now());
时间区间
// 获取今天的开始和结束时间
int today_start = logical_time.get_day_start(logical_time.now());
int today_end = logical_time.get_day_end(logical_time.now());
// 获取本月的开始和结束时间
int month_start = logical_time.get_month_start(logical_time.now());
int month_end = logical_time.get_month_end(logical_time.now());
// 获取本年的开始和结束时间
int year_start = logical_time.get_year_start(logical_time.now());
int year_end = logical_time.get_year_end(logical_time.now());
时间格式化
格式符 | 描述 | 示例 |
---|---|---|
%Y | 四位数的年份 | 2025 |
%y | 两位数的年份 | 25 |
%m | 两位数的月份(01-12) | 03 |
%B | 完整的月份名称 | March |
%b | 缩写的月份名称 | Mar |
%d | 两位数的日期(01-31) | 28 |
%e | 日期,前面不补零 (1-31) | 4 |
%H | 两位数的小时(24小时制,00-23) | 15 |
%I | 两位数的小时(12小时制,01-12) | 03 |
%p | AM/PM 标识 | PM |
%M | 两位数的分钟(00-59) | 30 |
%S | 两位数的秒数(00-59) | 45 |
%f | 三位数的毫秒数(000-999) | 038 |
%w | 一周中的第几天(0-6,0表示周日) | 5 |
%j | 一年中的第几天(001-366) | 087 |
%U | 一年中的第几周(00-53,周日为一周的第一天) | 12 |
%W | 一年中的第几周(00-53,周一为一周的第一天) | 12 |
%a | 缩写的星期名称 | Fri |
%A | 完整的星期名称 | Friday |
%c | 本地日期和时间表示 | Fri Mar 28 15:30:45 2025 |
%x | 本地日期表示 | 03/28/25 |
%X | 本地时间表示 | 15:30:45 |
%% | 字面上的百分号 | % |
// 格式化当前时间
string formatted = logical_time.format_local_time("%Y-%m-%d %H:%M:%S");
// 解析时间字符串
int timestamp = logical_time.parse_local_time("%Y-%m-%d %H:%M:%S", "2025-03-27 15:30:00");
// 自定义格式化
string custom = logical_time.format_local_time("今天是%A,%Y年%m月%d日");
事件处 理
// 注册每日重置回调
logical_time.register_daily_reset((: my_daily_reset_handler :));
// 注册时间暂停回调
logical_time.register_callback("time_pause", (: my_time_pause_handler :));
// 注册时间恢复回调
logical_time.register_callback("time_resume", (: my_time_resume_handler :));
每日重置偏移时间使用
// 注意:daily_reset_offset在启动时通过环境变量DAILY_RESET_OFFSET设定,运行时不可修改
// 获取当前重置偏移配置
int current_offset_hours = logical_time.get_daily_reset_offset_hours();
trace_info("当前重置偏移配置: %d小时", current_offset_hours);
// 获取当前重置周期的开始和结束时间
int cycle_start = logical_time.get_reset_day_start();
int cycle_end = logical_time.get_reset_day_end();
// 获取前一天的重置周期
int prev_start = logical_time.get_previous_reset_day_start();
int prev_end = logical_time.get_previous_reset_day_end();
// 获取下一天的重置周期
int next_start = logical_time.get_next_reset_day_start();
// 判断两个时间是否在同一个重置周期内
bool same_cycle = logical_time.is_same_reset_day(time1, time2);
// 判断一个时间是否在今天的重置周期内
bool is_today = logical_time.is_today_reset_cycle(some_timestamp);
// 计算两个时间之间跨越了多少个重置周期
int cycles_diff = logical_time.between_reset_days(time1, time2);
基于重置偏移时间的时间区间计算
// 获取当前时间在重置概念下的各种时间区间
int reset_day_start = logical_time.get_reset_day_start(); // 今天5:00
int reset_day_end = logical_time.get_reset_day_end(); // 明天4:59:59
int reset_week_start = logical_time.get_reset_week_start(); // 本周一5:00
int reset_week_end = logical_time.get_reset_week_end(); // 本周日4:59:59
int reset_month_start = logical_time.get_reset_month_start(); // 本月1号5:00
int reset_month_end = logical_time.get_reset_month_end(); // 下月1号4:59:59
int reset_year_start = logical_time.get_reset_year_start(); // 今年1月1号5:00
int reset_year_end = logical_time.get_reset_year_end(); // 明年1月1号4:59:59
// 与传统时间区间的对比
int traditional_day_start = logical_time.get_day_start(); // 今天0:00
int reset_day_start_5am = logical_time.get_reset_day_start(); // 今天5:00(或昨天5:00,取决于当前时间)
Previous/Next 重置时间区间使用
// 获取当前每日重置时间配置(不可运行时修改)
int current_reset_hours = logical_time.get_daily_reset_offset_hours();
// 获取前一天/下一天的重置区间
int prev_day_start = logical_time.get_previous_reset_day_start(); // 昨天5:00
int prev_day_end = logical_time.get_previous_reset_day_end(); // 今天4:59:59
int next_day_start = logical_time.get_next_reset_day_start(); // 明天5:00
int next_day_end = logical_time.get_next_reset_day_end(); // 后天4:59:59
// 获取前一周/下一周的重置区间
int prev_week_start = logical_time.get_previous_reset_week_start(); // 上周一5:00
int prev_week_end = logical_time.get_previous_reset_week_end(); // 上周日4:59:59
int next_week_start = logical_time.get_next_reset_week_start(); // 下周一5:00
int next_week_end = logical_time.get_next_reset_week_end(); // 下周日4:59:59
// 获取前一月/下一月的重置区间
int prev_month_start = logical_time.get_previous_reset_month_start(); // 上月1号5:00
int prev_month_end = logical_time.get_previous_reset_month_end(); // 本月1号4:59:59
int next_month_start = logical_time.get_next_reset_month_start(); // 下月1号5:00
int next_month_end = logical_time.get_next_reset_month_end(); // 下下月1号4:59:59
// 获取前一年/下一年的重置区间
int prev_year_start = logical_time.get_previous_reset_year_start(); // 去年1月1号5:00
int prev_year_end = logical_time.get_previous_reset_year_end(); // 今年1月1号4:59:59
int next_year_start = logical_time.get_next_reset_year_start(); // 明年1月1号5:00
int next_year_end = logical_time.get_next_reset_year_end(); // 后年1月1号4:59:59
// 游戏应用示例:检查玩家是否错过了上周的活动
bool missed_last_week_activity = (player_last_activity_time < prev_week_start);
注意事项
- 时间偏移量修改会影响所有基于逻辑时间的功能,请谨慎使用
- 时间暂停期间,获取的逻辑时间将保持在暂停时刻
- 注册的事件回调必须是合法的函数引用
- 事件回调会在异步协程中执行,处理回调逻辑时需注意线程安全
性能考虑
- 时间格式化和解析操作相对耗时,避免在高频循环中使用
- 时间偏移和暂停操作会在进程间同步并落地保存,避免频繁调用