2

I have a date like: 171115 183130 (17-11-15 18:31:30). I using an API that required me to supply the date based on the week number but since it's for a GPS service it needs to be the week number counting from 1980 (first epoch)

I couldn't find any library in C that takes into consideration leap days/seconds. Any ideas?

For example, week 1873 should be 2015 11 30.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
matt
  • 2,312
  • 5
  • 34
  • 57
  • See also [Ticks between Unix epoch and GPS epoch](https://stackoverflow.com/q/20521750/2410359) and [What is a GPS epoch?](https://gis.stackexchange.com/questions/281223/what-is-a-gps-epoch) – chux - Reinstate Monica Apr 09 '19 at 20:03

2 Answers2

4

By using difftime() no need to assume Jan 1, 1970 epoch. difftime() returns the difference in the 2 time stamps as a number of seconds (double). The return value is independent of the number type and epoch used for time_t.

Use mktime() to convert YMD to time_t.
Open question: timezone not mentioned in OP's post.

#include <stdio.h>
#include <time.h>

time_t TimeFromYMD(int year, int month, int day) {
  struct tm tm = {0};
  tm.tm_year = year - 1900;
  tm.tm_mon = month - 1;
  tm.tm_mday = day;
  return mktime(&tm);
}

#define SECS_PER_WEEK (60L*60*24*7)

int GPSweek(int year, int month, int day) {
  // See update below
  double diff = difftime(TimeFromYMD(year, month, day), TimeFromYMD(1980, 1, 1));  // See update
  return (int) (diff / SECS_PER_WEEK);
}

int main(void) {
  printf("%d\n", GPSweek(2015, 11, 30));
  return 0;
}

Output

1873

[edit 2022]

@Bianca offered the correction to use Jan 5, 1980 epoch. Reviewed against this and determine Jan 6, 1980 is correct which also matches this.

int GPSweek(int year, int month, int day) {
  double diff = difftime(TimeFromYMD(year, month, day), TimeFromYMD(1980, 1, 6));
  return (int) (diff / SECS_PER_WEEK);
}

Pedantic: Should a TZ setting include an area that has gained/lost a day due to switching across the International dateline, mktime() may be problematic.

Week numbers before Jan 6, 1980 need additional code.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • NOTE - The GPS epoch is 0000 UT (midnight) on January 6, 1980. GPS time is not adjusted and therefore is offset from UTC by an integer number of seconds, – Xofo Apr 09 '19 at 16:27
  • 1
    I order to make it work properly for the current date, inside the GPSweek function, TimeFromYMD(1980, 1, 1) should be changed to -> TimeFromYMD(1980, 1, 5). – IceCode Sep 28 '22 at 13:35
  • @Bianca Why Jan 5, 1980 and not [Jan 6, 1980](https://stackoverflow.com/questions/20521750/ticks-between-unix-epoch-and-gps-epoch)? – chux - Reinstate Monica Sep 28 '22 at 14:58
  • I personally don't have a technical explanation right now @chux-ReinstateMonica. I tested the algorithm and compared it to this website https://www.gnsscalendar.com/ and I obtained the correct results only by using Jan 5, 1980 instead of Jan 1, 1980. – IceCode Sep 28 '22 at 20:07
  • One potential explanation would be: "The starting point (time zero) of GPS time was chosen to be midnight of 5-6 January 1980" – IceCode Sep 28 '22 at 20:08
  • @Bianca My review concluded Jan 6, 1980. Please review. If is fails, please provide sample data as well as value from `difftime(TimeFromYMD(year, month, day), TimeFromYMD(1980, 1, 1))`. – chux - Reinstate Monica Sep 28 '22 at 22:00
  • @chux-ReinstateMonica Yes, Jan 5 still works for me instead of 6 Jan. Try for example a date like 2022 09 11 in the main function. With Jan 5 I will get 2227 which is correct, but with Jan 6 I will get 2226. – IceCode Sep 29 '22 at 06:41
  • @Bianca [as requested](https://stackoverflow.com/questions/34159790/how-can-i-get-the-gps-week-number-given-a-date-in-c/34160436?noredirect=1#comment130466332_34160436), what is the return value of `difftime(TimeFromYMD(year, month, day), TimeFromYMD(1980, 1, 1))` in the Jan 6, 1980 case - at least 17 significant places? e.g. `"%.17g"`. For me, it is `2227.0`. – chux - Reinstate Monica Sep 29 '22 at 07:00
3

Since the date shows the day and time separately, you do not need to worry about leap seconds.

Use the C library API to convert from DDMMYY to the number of seconds since the C epoch (1/1/1970), subtract the number of seconds until 1/1/1980 and divide the result by 7*24*3600 to get the number of weeks elapsed from 1/1/1980.

chqrlie
  • 131,814
  • 10
  • 121
  • 189