postgresql数据库插件pg_cron修改时区

前言:

pg_cron插件默认时区为GMT,对于其他时区的用户来说使用时要计算时区差异,比较繁琐。这篇博客通过修改pg_cron1.3的源码,来实现一种简单的更改时区方法。未经过详细测试,本人水平有限,可能会导致pg_cron出现问题,在此仅记录修改思路。

pg_cron源码改动

pg_cron中对于cron格式的解析在parse_cron_entry()函数中,该函数由vixie-cron的load_entry修改而来,事实上,pg_cron中对于cron的解析和执行判断很多逻辑都来自于vixie-cron,对于其具体逻辑的分析,本博客不再赘述。

在pg_cron中,对于job是否需要执行的判断在ShouldRunTask()函数中,源代码如下

static bool
ShouldRunTask(entry *schedule, TimestampTz currentTime, bool doWild,
			  bool doNonWild)
{
	time_t currentTime_t = timestamptz_to_time_t(currentTime);
	struct tm *tm = gmtime(&currentTime_t);

	int minute = tm->tm_min -FIRST_MINUTE;
	int hour = tm->tm_hour -FIRST_HOUR;
	int dayOfMonth = tm->tm_mday -FIRST_DOM;
	int month = tm->tm_mon +1 -FIRST_MONTH;
	int dayOfWeek = tm->tm_wday -FIRST_DOW;

	if (bit_test(schedule->minute, minute) &&
	    bit_test(schedule->hour, hour) &&
	    bit_test(schedule->month, month) &&
	    ( ((schedule->flags & DOM_STAR) || (schedule->flags & DOW_STAR))
	      ? (bit_test(schedule->dow,dayOfWeek) && bit_test(schedule->dom,dayOfMonth))
	      : (bit_test(schedule->dow,dayOfWeek) || bit_test(schedule->dom,dayOfMonth)))) {
		if ((doNonWild && !(schedule->flags & (MIN_STAR|HR_STAR)))
		    || (doWild && (schedule->flags & (MIN_STAR|HR_STAR))))
		{
			return true;
		}
	}

	return false;
}

关注点在于这两句代码

	time_t currentTime_t = timestamptz_to_time_t(currentTime);
	struct tm *tm = gmtime(&currentTime_t);

这两句的作用是将我们获取的currentTime转换为time_t格式,再用gmtime()函数来填充tm结构并用GMT时区表示,结构体格式如下

/* ISO C `broken-down time' structure.  */
struct tm
{
  int tm_sec;			/* Seconds.	[0-60] (1 leap second) */
  int tm_min;			/* Minutes.	[0-59] */
  int tm_hour;			/* Hours.	[0-23] */
  int tm_mday;			/* Day.		[1-31] */
  int tm_mon;			/* Month.	[0-11] */
  int tm_year;			/* Year	- 1900.  */
  int tm_wday;			/* Day of week.	[0-6] */
  int tm_yday;			/* Days in year.[0-365]	*/
  int tm_isdst;			/* DST.		[-1/0/1]*/

# ifdef	__USE_MISC
  long int tm_gmtoff;		/* Seconds east of UTC.  */
  const char *tm_zone;		/* Timezone abbreviation.  */
# else
  long int __tm_gmtoff;		/* Seconds east of UTC.  */
  const char *__tm_zone;	/* Timezone abbreviation.  */
# endif
};

因此,想要更改时区,就应当生成与数据库时区相同的tm结构体

gmtime()函数为c库函数,第一种方案我们可以使用同为c库函数的localtime(),但这个函数获取的是操作系统本地时区,返回的tm结构体以操作系统本地时区表示,但pg_cron是基于postgresql数据库的,数据库时区可能与操作系统本地时区不符。因此,我们使用postgresql的pg_localtime()函数。该函数的声明在pgtime.h中

extern struct pg_tm *pg_localtime(const pg_time_t *timep, const pg_tz *tz);

与localtime()函数相比,多了一个参数,该参数的作用是传入一个pg_tz结构体,用于自定义返回的pg_tm结构体的表现时区,具体使用代码如下。

pg_time_t currentTime_t = timestamptz_to_time_t(currentTime);
struct pg_tm *tm;
pg_tz *tz;

tz = pg_tzset("PRC");//东八区北京时间
if (!tz)
    return false;//也可以改成ereport报告一下错误

tm = pg_localtime(&currentTime_t, tz);

也可以创建一个系统参数,比如cron.time_zone,调用pg_tzset()函数时传入该参数,这样可以实现多时区改变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值