getUTC

Formatted documentation for the getUTC function.

Returns the UTC time. The value is in Matlab datenum format.

Contents

Description

For some applications it is necessary to know the current UTC time. This function will return the current UTC time in the datenum format.
There are several methods implemented in this function:

By default the system call will be tried first, followed by the C implementation, followed by the online implementation. By providing an override, you can bypass this order. Note that with the override the output will be empty if UTC determination fails, while with normal operation getUTC will throw an error.

Syntax

atomTime=getUTC
atomTime=getUTC(override)

Output arguments

atomTime The UTC time in the datenum format.

Input arguments

override If you provide an override, this function will no longer return an error, but the output will be empty instead.
You can force the use of the C implementation by providing 1 as override value, or 2 for the web version, or 3 for the system call. Any other value will trigger an error.

Compatibility, version info, and licence

Compatibility considerations:

Test suite result Windows XP/7/10 Ubuntu 20.04 LTS MacOS 10.15 Catalina
Matlab R2021a W10 : Pass
Matlab R2020b W10 : Pass
Matlab R2020a W10 : Pass
Matlab R2018a W10 : Pass Pass
Matlab R2015a W10 : Pass Pass
Matlab R2013b W10 : Partial: web failed
Matlab R2012b W10 : Partial: web failed
Matlab R2011a W10 : Partial: web failed Partial: web failed
Matlab R2010b Partial: web failed
Matlab R2010a W7 : Partial: web failed
Matlab R2007b W10 : Partial: web failed
Matlab 7.1 (R14SP3) XP : Partial: web failed
Matlab 6.5 (R13) W10 : Partial: web failed
Octave 6.2.0 W10 : Pass
Octave 5.2.0 W10 : Pass Pass
Octave 4.4.1 W10 : Pass Pass

Version: 2.0.1
Date:    2021-05-01
Author:  H.J. Wisselink
Licence: CC by-nc-sa 4.0 ( https://creativecommons.org/licenses/by-nc-sa/4.0 )
Email = 'h_j_wisselink*alumnus_utwente_nl';
Real_email = regexprep(Email,{'*','_'},{'@','.'})

Test suite

This tester is included so you can test if your own modifications would introduce any bugs. These tests form the basis for the compatibility table above.

To save space, the tester function below doesn't contain any comments. The full tester function (including all comments) can be found here.

% Test function for getUTC (an error for the web is expected for Matlab releases without websave)
%
% Pass:    passes all tests, failures for C method when no compiler is present
% Partial: web method fails (only when expected)
% Fail:    unexpected failures
%
function pass_part_fail=aaa___getUTC___test(varargin)
pass_part_fail='pass';
getUTC(1);
t1=now;
C=getUTC(1);
t1=(now-t1)*60*60*24;t2=now;
web=getUTC(2);
t2=(now-t2)*60*60*24;t3=now;
cmd=getUTC(3);
t3=(now-t3)*60*60*24;
isOctave=exist('OCTAVE_VERSION', 'builtin') ~= 0;
v=version;ind=strfind(v,'.');v=str2double(v(1:(ind(2)-1)));
fail=false;
if isempty(C)
    if CheckMexCompilerExistence
        fprintf('C function failed\n')
        fail=true;
    else
        fprintf('C function failed [no compiler found]\n')
    end
end
if ~isnetavl,web=0;end
if isempty(web)
    if ~isOctave && v<8.4
        fprintf('web function failed as expected\n')
        pass_part_fail='partial: web failed';
    else
        fail=true;fprintf('web function failed\n')
    end
elseif ~isOctave && v<8
    fail=true;fprintf('web function did not fail as expected\n')
end
if isempty(cmd)
	fail=true;fprintf('system call failed\n')
end
if fail
    if nargout>0
        pass_part_fail='fail';return
    else
        error('test failed')
    end
else
    fprintf('C function took %.2f seconds\n',t1)
    fprintf('web function took %.2f seconds\n',t2)
    fprintf('system call took %.2f seconds\n',t3)
    fprintf('test completed\n')
end
if nargout==0,clear,end
end
function [tf,ME]=CheckMexCompilerExistence
persistent tf_ ME_
if isempty(tf_)
    if ifversion('<',0,'Octave','>',0)
        tf_=true;
    elseif ifversion('>=','R2008a')
        try cc=mex.getCompilerConfigurations;catch,cc=[];end
        tf_=~isempty(cc);
    else
        if ispc,ext='.bat';else,ext='.sh';end
        tf_=exist(fullfile(prefdir,['mexopts' ext]),'file');
    end
    msg={...
        'No selected compiler was found. Please make sure a supported compiler is',...
        'installed and set up. Run mex(''-setup'') for version-specific documentation.',...
        '',...
        'Clear persistent variables (with clear(''all'') or clear(''functions''))',...
        'after running mex(''-setup'') to prevent this error.'};
    msg=sprintf('\n%s',msg{:});msg=msg(2:end);
    ME_=struct('identifier','HJW:CheckMexCompilerExistence:NoCompiler','message',msg);
end
tf=tf_;ME=ME_;
end
function atomTime=getUTC(override)
if nargin==0
    UTC_epoch_seconds=getUTC_cmd;
    if isempty(UTC_epoch_seconds)
        UTC_epoch_seconds=getUTC_c;
    end
    if isempty(UTC_epoch_seconds)
        UTC_epoch_seconds=getUTC_web;
    end
    if isempty(UTC_epoch_seconds)
        error('HJW:getUTC:TimeReadFailed',...
            ['All methods of retrieving the UTC timestamp failed.\nEnsure you ',...
            'have write access to the current folder and check your internet connection.'])
    end
else
    if override==1
        UTC_epoch_seconds=getUTC_c(false);
    elseif override==2
        UTC_epoch_seconds=getUTC_web;
    elseif override==3
        UTC_epoch_seconds=getUTC_cmd;
    else
        error('non-implemented override')
    end
end
UTC_offset=UTC_epoch_seconds/(24*60*60);
atomTime=UTC_offset+datenum(1970,1,1);
end
function UTC_epoch_seconds=getUTC_c(allow_rethrow)
if nargin==0,allow_rethrow=true;end
persistent utc_time_c tempdir_f funname utc_time_fun_handle Compile_attempts_remaining mexfilename
if isempty(utc_time_c)
    tempdir_f=fullfile(GetWritableFolder,'FileExchange','getUTC');
    try
        if isempty(strfind([path ';'],[tempdir_f ';']))
            if ~exist(tempdir_f,'dir'),mkdir(tempdir_f);end
            addpath(tempdir_f,'-end');
        end
    catch
    end
    funname='utc_time';
    [mexfilename,funname]=mexname(funname);
    try utc_time_fun_handle=str2func(funname);catch,end
    Compile_attempts_remaining=5;
    utc_time_c={'#include "mex.h"';
        '#include "time.h"';
        '';
        '/* Abraham Cohn,  3/17/2005 */';
        '/* Philips Medical Systems */';
        '';
        'void mexFunction(int nlhs, mxArray *plhs[], int nrhs,';
        '                 const mxArray *prhs[])';
        '{';
        '  time_t utc;';
        '  ';
        '  if (nlhs > 1) {';
        '    mexErrMsgTxt("Too many output arguments");';
        '  }';
        '  ';
        '  /* Here is a nice ref: www.cplusplus.com/ref/ctime/time.html */';
        '  time(&utc);';
        '  /* mexPrintf("UTC time in local zone: %s",ctime(&utc)); */';
        '  /* mexPrintf("UTC time in GMT: %s",asctime(gmtime(&utc))); */';
        '  ';
        '  /* Create matrix for the return argument. */';
        '  plhs[0] = mxCreateDoubleScalar((double)utc);';
        '   ';
        '}'};
end
try
    UTC_epoch_seconds=feval(utc_time_fun_handle);
catch
    if exist(mexfilename,'file')
        if allow_rethrow
            ME=lasterror;
            rethrow(ME);
        else
            UTC_epoch_seconds=[];return
        end
    end
    if ~CheckMexCompilerExistence
        Compile_attempts_remaining=0;
        UTC_epoch_seconds=[];return
    end
    Compile_attempts_remaining=Compile_attempts_remaining-1;
    if Compile_attempts_remaining<0
        UTC_epoch_seconds=[];return
    end
    if TestFolderWritePermission(tempdir_f)
        f=tempdir_f;
    else
        f=pwd;
    end
    current_folder=cd(f);
    try
        if ~exist(fullfile(f,[funname '.c']),'file')
            fid=fopen(fullfile(f,[funname '.c']),'w');
            for line=1:numel(utc_time_c)
                fprintf(fid,'%s\n',utc_time_c{line});
            end
            fclose(fid);
        end
        try
            mex([funname '.c']);
        catch
        end
        for ext={'c','o'}
            file=fullfile(f,[funname '.' ext{1}]);if exist(file,'file'),delete(file),end
        end
    catch
    end
    cd(current_folder);
    if exist(mexfilename,'file')
        utc_time_fun_handle=str2func(funname);
        UTC_epoch_seconds=getUTC_c(allow_rethrow);
    else
        UTC_epoch_seconds=[];
    end
end
end
function UTC_epoch_seconds=getUTC_cmd
persistent WinVer
if isempty(WinVer)
    try
        if ~ispc
            error('trigger')
        else
            [status,str]=system('systeminfo');
            ind1= 1+strfind(str,':');ind1=ind1(3);
            ind2=-1+strfind(str,'.');ind2(ind2<ind1)=[];
            WinVer=str2double(str(ind1:ind2(1)));
        end
    catch
        WinVer=NaN;
    end
end
try
    if ispc
        if isnan(WinVer)
            error('trigger')
        elseif WinVer<=5
            pausetime=1;
            fn1=[tempname,'.bat'];fn2=[tempname,'.txt'];
            fid=fopen(fn1,'w');
            fprintf(fid,'wmic os get LocalDateTime /value > "%s"\nexit',fn2);
            fclose(fid);
            system(['start /min "" cmd /c "' fn1 '"']);
            pause(pausetime)
            str=fileread(fn2);
            try delete(fn1);catch,end
            try delete(fn2);catch,end
        else
            pausetime=0;
            [status,str]=system('wmic os get LocalDateTime /value');
        end
        str=str(str>=43 & str<=57);
        date=mat2cell(str(1:21),1,[4 2 2,2 2 2+1+6]);date=str2double(date);
        date(5)=date(5)-str2double(str(22:end));
        date=num2cell(date);
        UTC_epoch_seconds=(datenum(date{:})-datenum(1970,1,1))*24*60*60;
        UTC_epoch_seconds=UTC_epoch_seconds+pausetime;
    else
        [status,str]=system('date +%s');
        UTC_epoch_seconds=str2double(str);
    end
catch
    UTC_epoch_seconds=[];
end
end
function UTC_epoch_seconds=getUTC_web
persistent UseWebread
if isempty(UseWebread)
    try UseWebread=~isempty(which(func2str(@webread)));catch,UseWebread=false;end
end
if ~isnetavl,UTC_epoch_seconds=[];return,end
for tries=1:3
    try
        if UseWebread
            data=webread('http://www.utctime.net/utc-timestamp');
        else
            data=urlread('http://www.utctime.net/utc-timestamp');
        end
        break
    catch
    end
end
try
    data(data==' ')='';
    pat='vartimestamp=';
    ind1=strfind(data,pat)+numel(pat);
    ind2=strfind(data,';')-1;
    ind2(ind2<ind1)=[];
    UTC_epoch_seconds=str2double(data(ind1:ind2(1)));
catch
    UTC_epoch_seconds=[];
end
end
function [f,status]=GetWritableFolder(varargin)
[success,options,ME]=GetWritableFolder_parse_inputs(varargin{:});
if ~success
    rethrow(ME)
else
    [ForceStatus,ErrorOnNotFound,root_folder_list]=deal(options.ForceStatus,...
        options.ErrorOnNotFound,options.root_folder_list);
end
root_folder_list{end}=pwd;
if ForceStatus
    status=ForceStatus;f=fullfile(root_folder_list{status},'PersistentFolder');
    try if ~exist(f,'dir'),mkdir(f);end,catch,end
    return
end
status=1;f=root_folder_list{status};
try if ~exist(f,'dir'),mkdir(f);end,catch,end
if ~TestFolderWritePermission(f)
    status=2;f=root_folder_list{status};
    try if ~exist(f,'dir'),mkdir(f);end,catch,end
    if ~TestFolderWritePermission(f)
        status=3;f=root_folder_list{status};
    end
end
f=fullfile(f,'PersistentFolder');
try if ~exist(f,'dir'),mkdir(f);end,catch,end
if ~TestFolderWritePermission(f)
    if ErrorOnNotFound
        error('HJW:GetWritableFolder:NoWritableFolder',...
            'This function was unable to find a folder with write permissions.')
    else
        status=0;f='';
    end
end
end
function [success,options,ME]=GetWritableFolder_parse_inputs(varargin)
success=false;
options=struct;
ME=struct('identifier','','message','');
persistent default
if isempty(default)
    default.ForceStatus=false;
    default.ErrorOnNotFound=false;
    default.root_folder_list={...
        GetPseudoAddonpath;
        fullfile(tempdir,'MATLAB');
        ''};
end
if nargin==2
    options=default;
    success=true;
    return
end
struct_input=       nargin   ==1 && isa(varargin{1},'struct');
NameValue_input=mod(nargin,2)==0 && all(...
    cellfun('isclass',varargin(1:2:end),'char'  ) | ...
    cellfun('isclass',varargin(1:2:end),'string')   );
if ~( struct_input || NameValue_input )
    ME.message=['The input is expected to be either a struct, ',char(10),...
        'or consist of Name,Value pairs.'];
    ME.identifier='HJW:GetWritableFolder:incorrect_input_options';
    return
end
if NameValue_input
    for n=1:2:numel(varargin)
        try
            options.(varargin{n})=varargin{n+1};
        catch
            ME.message='Parsing of Name,Value pairs failed.';
            ME.identifier='HJW:GetWritableFolder:incorrect_input_NameValue';
            return
        end
    end
else
    options=varargin{1};
end
fn=fieldnames(options);
for k=1:numel(fn)
    curr_option=fn{k};
    item=options.(curr_option);
    ME.identifier=['HJW:GetWritableFolder:incorrect_input_opt_' lower(curr_option)];
    switch curr_option
        case 'ForceStatus'
            try
                if ~isa(default.root_folder_list{item},'char')
                    error('the indexing must have failed, trigger error')
                end
            catch
                ME.message=sprintf('Invalid input: expected a scalar integer between 1 and %d.',...
                    numel(default.root_folder_list));
                return
            end
        case 'ErrorOnNotFound'
            [passed,options.ErrorOnNotFound]=test_if_scalar_logical(item);
            if ~passed
                ME.message='ErrorOnNotFound should be either true or false.';
                return
            end
        otherwise
            ME.message=sprintf('Name,Value pair not recognized: %s.',curr_option);
            ME.identifier='HJW:GetWritableFolder:incorrect_input_NameValue';
            return
    end
end
fn=fieldnames(default);
for k=1:numel(fn)
    if ~isfield(options,fn(k))
        options.(fn{k})=default.(fn{k});
    end
end
success=true;ME=[];
end
function f=GetPseudoAddonpath
if ispc
    [ignore,appdata]=system('echo %APPDATA%');appdata(appdata<14)='';
    f=fullfile(appdata,'MathWorks','MATLAB Add-Ons');
else
    [ignore,home_dir]=system('echo $HOME');home_dir(home_dir<14)='';
    f=fullfile(home_dir,'Documents','MATLAB','Add-Ons');
end
end
function tf=ifversion(test,Rxxxxab,Oct_flag,Oct_test,Oct_ver)
persistent  v_num v_dict octave
if isempty(v_num)
    octave=exist('OCTAVE_VERSION', 'builtin');
    v_num=version;
    ii=strfind(v_num,'.');if numel(ii)~=1,v_num(ii(2):end)='';ii=ii(1);end
    v_num=[str2double(v_num(1:(ii-1))) str2double(v_num((ii+1):end))];
    v_num=v_num(1)+v_num(2)/100;v_num=round(100*v_num);
    v_dict={...
        'R13' 605;'R13SP1' 605;'R13SP2' 605;'R14' 700;'R14SP1' 700;'R14SP2' 700;
        'R14SP3' 701;'R2006a' 702;'R2006b' 703;'R2007a' 704;'R2007b' 705;
        'R2008a' 706;'R2008b' 707;'R2009a' 708;'R2009b' 709;'R2010a' 710;
        'R2010b' 711;'R2011a' 712;'R2011b' 713;'R2012a' 714;'R2012b' 800;
        'R2013a' 801;'R2013b' 802;'R2014a' 803;'R2014b' 804;'R2015a' 805;
        'R2015b' 806;'R2016a' 900;'R2016b' 901;'R2017a' 902;'R2017b' 903;
        'R2018a' 904;'R2018b' 905;'R2019a' 906;'R2019b' 907;'R2020a' 908;
        'R2020b' 909;'R2021a' 910};
end
if octave
    if nargin==2
        warning('HJW:ifversion:NoOctaveTest',...
            ['No version test for Octave was provided.',char(10),...
            'This function might return an unexpected outcome.'])
        if isnumeric(Rxxxxab)
            v=0.1*Rxxxxab+0.9*fix(Rxxxxab);v=round(100*v);
        else
            L=ismember(v_dict(:,1),Rxxxxab);
            if sum(L)~=1
                warning('HJW:ifversion:NotInDict',...
                    'The requested version is not in the hard-coded list.')
                tf=NaN;return
            else
                v=v_dict{L,2};
            end
        end
    elseif nargin==4
        [test,v]=deal(Oct_flag,Oct_test);
        v=0.1*v+0.9*fix(v);v=round(100*v);
    else
        [test,v]=deal(Oct_test,Oct_ver);
        v=0.1*v+0.9*fix(v);v=round(100*v);
    end
else
    if isnumeric(Rxxxxab)
        v=0.1*Rxxxxab+0.9*fix(Rxxxxab);v=round(100*v);
    else
        L=ismember(v_dict(:,1),Rxxxxab);
        if sum(L)~=1
            warning('HJW:ifversion:NotInDict',...
                'The requested version is not in the hard-coded list.')
            tf=NaN;return
        else
            v=v_dict{L,2};
        end
    end
end
switch test
    case '==', tf= v_num == v;
    case '<' , tf= v_num <  v;
    case '<=', tf= v_num <= v;
    case '>' , tf= v_num >  v;
    case '>=', tf= v_num >= v;
end
end
function [connected,timing]=isnetavl(test_Matlab_instead_of_system)
if nargin==0,                                                        tf=false;
else,[tf1,tf2]=test_if_scalar_logical(test_Matlab_instead_of_system);tf=tf1&&tf2;
end
if tf
    [connected,timing]=isnetavl___ping_via_html;
    return
end
tf=isnetavl__ICMP_is_blocked;
if isempty(tf)
    connected=0;
    timing=0;
else
    if tf
        [connected,timing]=isnetavl___ping_via_html;
    else
        [connected,timing]=isnetavl___ping_via_system;
    end
end
end
function [connected,timing]=isnetavl___ping_via_html
persistent UseWebread
if isempty(UseWebread)
    try no_webread=isempty(which(func2str(@webread)));catch,no_webread=true;end
	UseWebread=~no_webread;
end
try
    then=now;
    if UseWebread
        str=webread('http://google.com');
    else
        str=urlread('http://google.com');
    end
    connected=1;
    timing=(now-then)*24*3600*1000;
catch
    connected=0;
    timing=0;
end
end
function [connected,timing]=isnetavl___ping_via_system
if ispc
    try
        [ignore_output,b]=system('ping -n 1 8.8.8.8');
        stats=b(strfind(b,' = ')+3);
        stats=stats(1:3);
        if ~strcmp(stats,'110')
            error('trigger error')
        else
            connected=1;
            [ind1,ind2]=regexp(b,' [0-9]+ms');
            timing=b((ind1(1)+1):(ind2(1)-2));
            timing=str2double(timing);
        end
    catch
        connected=0;
        timing=0;
    end
elseif isunix
    try
        [ignore_output,b]=system('ping -c 1 8.8.8.8');
        ind=regexp(b,', [01] ');
        if b(ind+2)~='1'
            error('trigger error')
        else
            connected=1;
            [ind1,ind2]=regexp(b,'=[0-9.]+ ms');
            timing=b((ind1(1)+1):(ind2(1)-2));
            timing=str2double(timing);
        end
    catch
        connected=0;
        timing=0;
    end
else
    error('How did you even get Matlab to work?')
end
end
function [tf,connected,timing]=isnetavl__ICMP_is_blocked
persistent output
if ~isempty(output)
    tf=output;return
end
[connected,timing]=isnetavl___ping_via_system;
if connected
    output=false;
    tf=false;
    return
end
[connected,timing]=isnetavl___ping_via_html;
if connected
    output=true;
    tf=true;
    return
end
tf=[];
end
function [mex_filename,fun_name]=mexname(fun_name)
persistent append
if isempty(append)
    v=version;ind=strfind(v,'.');v(ind(2):end)='';v=['v' strrep(v,'.','_')];
    if ~exist('OCTAVE_VERSION', 'builtin')
        type=computer;
    else
        arch=computer;arch=arch(1:(min(strfind(arch,'-'))-1));
        if ispc
            if strcmp(arch,'x86_64')  ,type= 'win_64';
            elseif strcmp(arch,'i686'),type= 'win_i686';
            elseif strcmp(arch,'x86') ,type= 'win_x86';
            else                      ,type=['win_' arch];
            end
        elseif isunix && ~ismac
            if strcmp(arch,'i686')      ,type= 'lnx_i686';
            elseif strcmp(arch,'x86_64'),type= 'lnx_64';
            else                        ,type=['lnx_' arch];
            end
        elseif ismac
            if strcmp(arch,'x86_64'),type= 'mac_64';
            else                    ,type=['mac_' arch];
            end
        end
    end
    type=strrep(strrep(type,'.',''),'-','');
    append=cell(2,1);
    append{1}=['_' v '_' type];
    append{2}=[append{1} '.' mexext];
end
try
    if ~isvarname(fun_name),error('trigger catch block'),end
catch
    error('HJW:mexname:InvalidName','The provided input can''t be a function name')
end
mex_filename=[fun_name append{2}];
fun_name=[fun_name append{1}];
end
function [isLogical,val]=test_if_scalar_logical(val)
persistent states
if isempty(states)
    states={true,false;...
        1,0;...
        'on','off';...
        'enable','disable';...
        'enabled','disabled'};
    try
        states(end+1,:)=eval('{"on","off"}');
    catch
    end
end
isLogical=true;
try
    if isa(val,'char') || isa(val,'string')
        try val=lower(val);catch,end
    end
    for n=1:size(states,1)
        for m=1:2
            if isequal(val,states{n,m})
                val=states{1,m};return
            end
        end
    end
    if isa(val,'matlab.lang.OnOffSwitchState')
        val=logical(val);return
    end
catch
end
isLogical=false;
end
function tf=TestFolderWritePermission(f)
if ~( isempty(f) || exist(f,'dir') )
    tf=false;return
end
fn='';
while isempty(fn) || exist(fn,'file')
    [ignore,fn]=fileparts(tmpname('write_permission_test_','.txt'));
    fn=fullfile(f,fn);
end
try
    fid=fopen(fn,'w');fprintf(fid,'test');fclose(fid);
    delete(fn);
    tf=true;
catch
    if exist(fn,'file'),try delete(fn);catch,end,end
    tf=false;
end
end
function str=tmpname(StartFilenameWith,ext)
if nargin<1,StartFilenameWith='';end
if ~isempty(StartFilenameWith),StartFilenameWith=[StartFilenameWith '_'];end
if nargin<2,ext='';else,if ~strcmp(ext(1),'.'),ext=['.' ext];end,end
str=tempname;
[p,f]=fileparts(str);
str=fullfile(p,[StartFilenameWith f ext]);
end