summaryrefslogtreecommitdiff
path: root/sql-common/my_time.c
diff options
context:
space:
mode:
authorunknown <guilhem@mysql.com>2004-07-29 23:25:58 +0200
committerunknown <guilhem@mysql.com>2004-07-29 23:25:58 +0200
commit88e3aead85b7136fab3d8cfcfa19174c4c2e2662 (patch)
tree2f01af661dcc90a418853b7a1718fd7a0fe688e1 /sql-common/my_time.c
parent5ef15478cdbaa65c7d037ce5662117b8ed425dba (diff)
downloadmariadb-git-88e3aead85b7136fab3d8cfcfa19174c4c2e2662.tar.gz
WL#1580: --start-datetime, --stop-datetime, --start-position (alias for --position) and --stop-position
options for mysqlbinlog, with a test file. This enables user to say "recover my database to how it was this morning at 10:30" (mysqlbinlog "--stop-datetime=2003-07-29 10:30:00"). Using time functions into client/ made me move them out of sql/ into sql-common/. + (small) fix for BUG#4507 "mysqlbinlog --read-from-remote-server sometimes cannot accept 2 binlogs" (that is, on command line). client/client_priv.h: new options for mysqlbinlog client/mysqlbinlog.cc: WL#1580: --start-datetime, --stop-datetime, --start-position (alias for --position) and --stop-position. (small) fix for BUG#4507 "mysqlbinlog --read-from-remote-server sometimes cannot accept 2 binlogs". include/my_time.h: importing time functions so that client/ files can use them. include/mysql_time.h: importing time types so that client/ files can use them. sql-common/my_time.c: importing time functions so that client/ files can use them. sql/mysql_priv.h: moving time functions out of sql/ into sql-common/ sql/time.cc: moving time functions out of sql/ into sql-common/ sql/tztime.h: moving time functions out of sql/ into sql-common/
Diffstat (limited to 'sql-common/my_time.c')
-rw-r--r--sql-common/my_time.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 46c84ac9ba7..24c19be47ba 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -35,6 +35,16 @@ static uchar internal_format_positions[]=
static char time_separator=':';
+static ulong const days_at_timestart=719528; /* daynr at 1970.01.01 */
+uchar days_in_month[]= {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
+
+/*
+ Offset of system time zone from UTC in seconds used to speed up
+ work of my_system_gmt_sec() function.
+*/
+static long my_time_zone=0;
+
+
/*
Convert a timestamp string to a MYSQL_TIME value.
@@ -559,3 +569,148 @@ fractional:
}
+/*
+ Prepare offset of system time zone from UTC for my_system_gmt_sec() func.
+
+ SYNOPSIS
+ init_time()
+*/
+void init_time(void)
+{
+ time_t seconds;
+ struct tm *l_time,tm_tmp;;
+ MYSQL_TIME my_time;
+ bool not_used;
+
+ seconds= (time_t) time((time_t*) 0);
+ localtime_r(&seconds,&tm_tmp);
+ l_time= &tm_tmp;
+ my_time_zone= 3600; /* Comp. for -3600 in my_gmt_sec */
+ my_time.year= (uint) l_time->tm_year+1900;
+ my_time.month= (uint) l_time->tm_mon+1;
+ my_time.day= (uint) l_time->tm_mday;
+ my_time.hour= (uint) l_time->tm_hour;
+ my_time.minute= (uint) l_time->tm_min;
+ my_time.second= (uint) l_time->tm_sec;
+ my_system_gmt_sec(&my_time, &my_time_zone, &not_used); /* Init my_time_zone */
+}
+
+
+ /* Calculate nr of day since year 0 in new date-system (from 1615) */
+
+long calc_daynr(uint year,uint month,uint day)
+{
+ long delsum;
+ int temp;
+ DBUG_ENTER("calc_daynr");
+
+ if (year == 0 && month == 0 && day == 0)
+ DBUG_RETURN(0); /* Skip errors */
+ if (year < 200)
+ {
+ if ((year=year+1900) < 1900+YY_PART_YEAR)
+ year+=100;
+ }
+ delsum= (long) (365L * year+ 31*(month-1) +day);
+ if (month <= 2)
+ year--;
+ else
+ delsum-= (long) (month*4+23)/10;
+ temp=(int) ((year/100+1)*3)/4;
+ DBUG_PRINT("exit",("year: %d month: %d day: %d -> daynr: %ld",
+ year+(month <= 2),month,day,delsum+year/4-temp));
+ DBUG_RETURN(delsum+(int) year/4-temp);
+} /* calc_daynr */
+
+
+/*
+ Convert time in MYSQL_TIME representation in system time zone to its
+ my_time_t form (number of seconds in UTC since begginning of Unix Epoch).
+
+ SYNOPSIS
+ my_system_gmt_sec()
+ t - time value to be converted
+ my_timezone - pointer to long where offset of system time zone
+ from UTC will be stored for caching
+ in_dst_time_gap - set to true if time falls into spring time-gap
+
+ NOTES
+ The idea is to cache the time zone offset from UTC (including daylight
+ saving time) for the next call to make things faster. But currently we
+ just calculate this offset during startup (by calling init_time()
+ function) and use it all the time.
+ Time value provided should be legal time value (e.g. '2003-01-01 25:00:00'
+ is not allowed).
+
+ RETURN VALUE
+ Time in UTC seconds since Unix Epoch representation.
+*/
+my_time_t
+my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
+{
+ uint loop;
+ time_t tmp;
+ struct tm *l_time,tm_tmp;
+ long diff, current_timezone;
+
+ /*
+ Calculate the gmt time based on current time and timezone
+ The -1 on the end is to ensure that if have a date that exists twice
+ (like 2002-10-27 02:00:0 MET), we will find the initial date.
+
+ By doing -3600 we will have to call localtime_r() several times, but
+ I couldn't come up with a better way to get a repeatable result :(
+
+ We can't use mktime() as it's buggy on many platforms and not thread safe.
+ */
+ tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
+ (long) days_at_timestart)*86400L + (long) t->hour*3600L +
+ (long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
+ 3600);
+ current_timezone= my_time_zone;
+
+ localtime_r(&tmp,&tm_tmp);
+ l_time=&tm_tmp;
+ for (loop=0;
+ loop < 2 &&
+ (t->hour != (uint) l_time->tm_hour ||
+ t->minute != (uint) l_time->tm_min);
+ loop++)
+ { /* One check should be enough ? */
+ /* Get difference in days */
+ int days= t->day - l_time->tm_mday;
+ if (days < -1)
+ days= 1; // Month has wrapped
+ else if (days > 1)
+ days= -1;
+ diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) +
+ (long) (60*((int) t->minute - (int) l_time->tm_min)));
+ current_timezone+= diff+3600; // Compensate for -3600 above
+ tmp+= (time_t) diff;
+ localtime_r(&tmp,&tm_tmp);
+ l_time=&tm_tmp;
+ }
+ /*
+ Fix that if we are in the not existing daylight saving time hour
+ we move the start of the next real hour
+ */
+ if (loop == 2 && t->hour != (uint) l_time->tm_hour)
+ {
+ int days= t->day - l_time->tm_mday;
+ if (days < -1)
+ days=1; // Month has wrapped
+ else if (days > 1)
+ days= -1;
+ diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour))+
+ (long) (60*((int) t->minute - (int) l_time->tm_min)));
+ if (diff == 3600)
+ tmp+=3600 - t->minute*60 - t->second; // Move to next hour
+ else if (diff == -3600)
+ tmp-=t->minute*60 + t->second; // Move to previous hour
+
+ *in_dst_time_gap= 1;
+ }
+ *my_timezone= current_timezone;
+
+ return (my_time_t) tmp;
+} /* my_system_gmt_sec */