|
|
function [utcTime] = Gps2Utc(gpsTime) |
|
|
% [utcTime] = Gps2Utc(gpsTime) |
|
|
% Convert GPS time (week & seconds) to UTC |
|
|
% |
|
|
% Input: gpsTime, [mx2] matrix [gpsWeek, gpsSeconds], |
|
|
% |
|
|
% Outputs: utcTime, [mx6] matrix = [year,month,day,hours,minutes,seconds] |
|
|
% |
|
|
% Valid range of inputs: |
|
|
% gps times corresponding to 1980/6/1 <= time < 2100/1/1 |
|
|
% i.e. [0,0] <= gpsTime < [6260, 432000] |
|
|
% |
|
|
% See also: Utc2Gps |
|
|
|
|
|
% Other functions needed: LeapSeconds.m |
|
|
|
|
|
%Author: Frank van Diggelen |
|
|
%Open Source code for processing Android GNSS Measurements |
|
|
|
|
|
%Algorithm for handling leap seconds: |
|
|
% When a leap second happens, utc time stands still for one second, so |
|
|
% gps seconds get further ahead, so we subtract leapSecs to move from gps time |
|
|
% |
|
|
% 1) convert gpsTime to time = [yyyy,mm,dd,hh,mm,ss] (with no leap seconds) |
|
|
% 2) look up leap seconds for time: ls = LeapSeconds(time); |
|
|
% This is (usually) the correct leap second value. Unless: |
|
|
% If (utcTime=time) and (utcTime=time+ls) straddle a leap second |
|
|
% then we need to add 1 to ls |
|
|
% So, after step 2) ... |
|
|
% 3) convert gpsTime-ls to timeMLs |
|
|
% 4) look up leap seconds: ls1 = LeapSeconds(timeMLs); |
|
|
% 5) if ls1~=ls, convert (gpsTime-ls1) to UTC Time |
|
|
|
|
|
%% Check inputs |
|
|
if size(gpsTime,2)~=2 |
|
|
error('gpsTime must have two columns') |
|
|
end |
|
|
fctSeconds = gpsTime*[GpsConstants.WEEKSEC; 1]; |
|
|
%fct at 2100/1/1 00:00:00, not counting leap seconds: |
|
|
fct2100 = [6260, 432000]*[GpsConstants.WEEKSEC; 1]; |
|
|
if any(fctSeconds<0) || any (fctSeconds >= fct2100) |
|
|
error('gpsTime must be in this range: [0,0] <= gpsTime < [6260, 432000]'); |
|
|
end |
|
|
%% Finished checks |
|
|
|
|
|
%from now on work with fct |
|
|
%% Apply algorithm for handling leaps seconds |
|
|
% 1) convert gpsTime to time = [yyyy,mm,dd,hh,mm,ss] (with no leap seconds) |
|
|
time = Fct2Ymdhms(fctSeconds); |
|
|
% 2) look up leap seconds for time: ls = LeapSeconds(time); |
|
|
ls = LeapSeconds(time); |
|
|
% 3) convert gpsTime-ls to timeMLs |
|
|
timeMLs = Fct2Ymdhms(fctSeconds-ls); |
|
|
% 4) look up leap seconds: ls1 = LeapSeconds(timeMLs); |
|
|
ls1 = LeapSeconds(timeMLs); |
|
|
% 5) if ls1~=ls, convert (gpsTime-ls1) to UTC Time |
|
|
if all(ls1==ls) |
|
|
utcTime = timeMLs; |
|
|
else |
|
|
utcTime = Fct2Ymdhms(fctSeconds-ls1); |
|
|
end |
|
|
|
|
|
% NOTE: |
|
|
% Gps2Utc.m doesn't produce 23:59:60, at a leap second. |
|
|
% Instead, as the leap second occurs, the Gps2Utc.m sequence of |
|
|
% UTC hh:mm:ss is 23:59:59, 00:00:00, 00:00:00 |
|
|
% and we keep it like that for code simplicity. |
|
|
% Here are a sequence of UTC and GPS times around a leap second: |
|
|
% formalUtcTimes = [1981 12 31 23 59 59; 1981 12 31 23 59 60; 1982 1 1 0 0 0]; |
|
|
% gpsTimes = [103 431999; 103 432000; 103 432001]; |
|
|
% >> Gps2Utc(gpsTimes) |
|
|
% ans = |
|
|
% 1981 12 31 23 59 59 |
|
|
% 1982 1 1 0 0 0 |
|
|
% 1982 1 1 0 0 0 |
|
|
|
|
|
% If you want to change this you could check LeapSeconds.m to see if you're |
|
|
% exactly on the addition of a leap second, and then change the UTC format |
|
|
% to include the '60' seconds |
|
|
|
|
|
end %end of function Gps2Utc |
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
|
|
|
|
function time = Fct2Ymdhms(fctSeconds) |
|
|
%Utility function for Gps2Utc |
|
|
%Convert GPS full cycle time to [yyyy,mm,dd,hh,mm,ss.s] format |
|
|
HOURSEC = 3600; MINSEC = 60; |
|
|
monthDays=[31,28,31,30,31,30,31,31,30,31,30,31];%days each month (not leap year) |
|
|
|
|
|
m=length(fctSeconds); |
|
|
days = floor(fctSeconds / GpsConstants.DAYSEC) + 6;%days since 1980/1/1 |
|
|
years=zeros(m,1)+1980; |
|
|
%decrement days by a year at a time, until we have calculated the year: |
|
|
leap=ones(m,1); %1980 was a leap year |
|
|
while (any(days > (leap+365))) |
|
|
I = find(days > (leap+365) ); |
|
|
days(I) = days(I) - (leap(I) + 365); |
|
|
years(I)=years(I)+1; |
|
|
leap(I) = (rem(years(I),4) == 0); % leap = 1 on a leap year, 0 otherwise |
|
|
% This works from 1901 till 2099, 2100 isn't a leap year (2000 is). |
|
|
% Calculate the year, ie time(1) |
|
|
end, |
|
|
time=zeros(m,6);%initialize matrix |
|
|
time(:,1)=years; |
|
|
|
|
|
%decrement days by a month at a time, until we have calculated the month |
|
|
% Calculate the month, ie time(:,2) |
|
|
% Loop through m: |
|
|
for i=1:m |
|
|
month = 1; |
|
|
if (rem(years(i),4) == 0) %This works from 1901 till 2099 |
|
|
monthDays(2)=29; %Make February have 29 days in a leap year |
|
|
else |
|
|
monthDays(2)=28; |
|
|
end |
|
|
while (days(i) > monthDays(month)) |
|
|
days(i) = days(i)-monthDays(month); |
|
|
month = month+1; |
|
|
end |
|
|
time(i,2)=month; |
|
|
end |
|
|
|
|
|
time(:,3) = days; |
|
|
|
|
|
sinceMidnightSeconds = rem(fctSeconds, GpsConstants.DAYSEC); |
|
|
time(:,4) = fix(sinceMidnightSeconds/HOURSEC); |
|
|
lastHourSeconds = rem(sinceMidnightSeconds, HOURSEC); |
|
|
time(:,5) = fix(lastHourSeconds/MINSEC); |
|
|
time(:,6) = rem(lastHourSeconds,MINSEC); |
|
|
|
|
|
end %end of function Fct2Ymdhms |
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
|
|
|
|
|
|
|
% Copyright 2016 Google Inc. |
|
|
% |
|
|
% Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
% you may not use this file except in compliance with the License. |
|
|
% You may obtain a copy of the License at |
|
|
% |
|
|
% http://www.apache.org/licenses/LICENSE-2.0 |
|
|
% |
|
|
% Unless required by applicable law or agreed to in writing, software |
|
|
% distributed under the License is distributed on an "AS IS" BASIS, |
|
|
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
% See the License for the specific language governing permissions and |
|
|
% limitations under the License. |
|
|
|
|
|
|