Is there a package that allows to write correctly times in hours, minutes and seconds in mathematical mode?
Just slightly modifying your code:
\documentclass{article}
\usepackage{ifmtarg}
\usepackage{siunitx}
\sisetup{number-unit-separator=\,}
\makeatletter
\newcommand{\sitime}[1]{\sitime@aux#1;;;\@nil}
\def\sitime@aux#1;#2;#3;#4\@nil{%
\@ifmtarg{#1#2#3}%
{%
\PackageError{siunitx (modified)}%
{Empty \string\sitime\space argument}{}%
}%
{%
\@ifmtarg{#1}{}{\SI{#1}{\hour}\@ifmtarg{#2#3}{}{\csname l_siunitx_number_unit_separator_tl\endcsname}}%
\@ifmtarg{#2}{}{~ \SI{#2}{\minute}\@ifmtarg{#3}{}{\csname l_siunitx_number_unit_separator_tl\endcsname}}%
\@ifmtarg{#3}{}{~\SI{#3}{\second}}%
}%
}
\makeatother
\newcommand{\sep}{\qquad}
\begin{document}
$\sitime{10;7;12}-\sitime{9;13;8}$
\end{document}
Modified code to use :
as a separator for the arguments: use
\makeatletter
\newcommand{\sitime}[1]{\sitime@aux#1:::\@nil}
\def\sitime@aux#1:#2:#3:#4\@nil{%
\@ifmtarg{#1#2#3}%
{%
\PackageError{siunitx (modified)}%
{Empty \string\sitime\space argument}{}%
}%
{%
\@ifmtarg{#1}{}{\SI{#1}{\hour}\@ifmtarg{#2#3}{}{\csname l_siunitx_number_unit_separator_tl\endcsname}}%
\@ifmtarg{#2}{}{\ \SI{#2}{\minute}\@ifmtarg{#3}{}{\csname l_siunitx_number_unit_separator_tl\endcsname}}%
\@ifmtarg{#3}{}{\ \SI{#3}{\second}}%
}%
}
\makeatother
You can have a friendly syntax:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\hms}{ >{\SplitArgument{2}{;}}m }
{
\ensuremath{\andrec_hms:nnn #1}
}
\cs_new_protected:Nn \andrec_hms:nnn
{
\group_begin:
\bool_set_false:N \l__andrec_hms_thinspace_bool
\__andrec_hms_print:nn { 0#1 } { h }
\tl_if_novalue:nTF { #2 }
{
\__andrec_hms_print:nn { 0 } { m }
}
{
\__andrec_hms_print:nn { 0#2 } { m }
}
\tl_if_novalue:nTF { #3 }
{
\__andrec_hms_print:nn { 0 } { s }
}
{
\__andrec_hms_print:nn { 0#3 } { s }
}
\group_end:
}
\cs_new_protected:Nn \__andrec_hms_print:nn
{
\int_compare:nT { #1 != 0 }
{
\bool_if:NT \l__andrec_hms_thinspace_bool { \, }
\int_eval:n { #1 } \, \mathrm{#2}
\bool_set_true:N \l__andrec_hms_thinspace_bool
}
}
\ExplSyntaxOff
\begin{document}
$\hms{7;40;21}+\hms{3;17;5}+\hms{2;4;20}$
$\hms{12;41;}+\hms{0;47;20}+\hms{7;0;37}$
$\hms{5;12;45}-\hms{4;9}$
\end{document}
For a missing value you can use 0 or nothing; a trailing missing value can be omitted altogether; so for 2 hours you can say \hms{2}
, for 2 hours and 2 minutes \hms{2;2}
.
With a separator that can be set or reset at runtime, and also chosen as an optional argument:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\hms}{ o m }
{
\ensuremath
{
\IfNoValueTF { #1 }
{
\andrec_hms:Ve \l_andrec_hms_sep_str { \tl_to_str:n { #2 } }
}
{
\andrec_hms:ee { \tl_to_str:n { #1 } } { \tl_to_str:n { #2 } }
}
}
}
\NewDocumentCommand{\sethmssep}{m}
{
\str_set:Nn \l_andrec_hms_sep_str { #1 }
}
\cs_new_protected:Nn \andrec_hms:nn
{
\group_begin:
\seq_set_split:Nnn \l__andrec_hms_seq { #1 } { #2 }
% normalize the sequence to have three (or more!) items
\int_compare:nT { \seq_count:N \l__andrec_hms_seq = 1 }
{
\seq_put_right:Nn \l__andrec_hms_seq { 0 }
}
\int_compare:nT { \seq_count:N \l__andrec_hms_seq = 2 }
{
\seq_put_right:Nn \l__andrec_hms_seq { 0 }
}
% print
\bool_set_false:N \l__andrec_hms_thinspace_bool
\__andrec_hms_print:nn { 1 } { h }
\__andrec_hms_print:nn { 2 } { m }
\__andrec_hms_print:nn { 3 } { s }
\group_end:
}
\cs_generate_variant:Nn \andrec_hms:nn { Ve,ee }
\cs_new_protected:Nn \__andrec_hms_print:nn
{
\int_compare:nF { 0\seq_item:Nn \l__andrec_hms_seq { #1 } = 0 }
{
\bool_if:NT \l__andrec_hms_thinspace_bool { \, }
\int_eval:n { 0\seq_item:Nn \l__andrec_hms_seq { #1 } } \, \mathrm{#2}
\bool_set_true:N \l__andrec_hms_thinspace_bool
}
}
\ExplSyntaxOff
\sethmssep{:}
\begin{document}
$\hms{7:40:21}+\hms[;]{3;17;5}+\hms{2:4:20}$
\sethmssep{;}
$\hms{12;41;}+\hms{0;47;20}+\hms{7;0;37}$
\sethmssep{,}
$\hms{5,12,45}-\hms[;]{4;9}$
\end{document}
The output is the same. Using “stringifications”, we overcome the problems with babel.
So long as you don't want negative numbers, here's a modification that allows decimal numbers in the input. Note that you have to input the figures with a decimal point nontheless, but the output can be made to respect the locale.
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage{xparse}
\usepackage{siunitx}
\sisetup{locale=FR}
\ExplSyntaxOn
\NewDocumentCommand{\hms}{ o m }
{
\ensuremath
{
\IfNoValueTF { #1 }
{
\andrec_hms:Ve \l_andrec_hms_sep_str { \tl_to_str:n { #2 } }
}
{
\andrec_hms:ee { \tl_to_str:n { #1 } } { \tl_to_str:n { #2 } }
}
}
}
\NewDocumentCommand{\sethmssep}{m}
{
\str_set:Nn \l_andrec_hms_sep_str { #1 }
}
\cs_new_protected:Nn \andrec_hms:nn
{
\group_begin:
\seq_set_split:Nnn \l__andrec_hms_seq { #1 } { #2 }
% normalize the sequence to have three (or more!) items
\int_compare:nT { \seq_count:N \l__andrec_hms_seq = 1 }
{
\seq_put_right:Nn \l__andrec_hms_seq { 0 }
}
\int_compare:nT { \seq_count:N \l__andrec_hms_seq = 2 }
{
\seq_put_right:Nn \l__andrec_hms_seq { 0 }
}
% print
\bool_set_false:N \l__andrec_hms_thinspace_bool
\__andrec_hms_print:nn { 1 } { h }
\__andrec_hms_print:nn { 2 } { m }
\__andrec_hms_print:nn { 3 } { s }
\group_end:
}
\cs_generate_variant:Nn \andrec_hms:nn { Ve,ee }
\cs_new_protected:Nn \__andrec_hms_print:nn
{
\fp_compare:nF { 0\seq_item:Nn \l__andrec_hms_seq { #1 } = 0 }
{
\bool_if:NT \l__andrec_hms_thinspace_bool { \, }
\num{\fp_eval:n { 0\seq_item:Nn \l__andrec_hms_seq { #1 } }} \, \mathrm{#2}
\bool_set_true:N \l__andrec_hms_thinspace_bool
}
}
\ExplSyntaxOff
\sethmssep{:}
\begin{document}
$\hms{1.5::}=\num{1.5}\times\hms{:60:}=\hms{:90:}$ % new
$\hms{7:40:21}+\hms[;]{3;17;5}+\hms{2:4:20}$
\sethmssep{;}
$\hms{12;41;}+\hms{0;47;20}+\hms{7;0;37}$
\sethmssep{,}
$\hms{5,12,45}-\hms[;]{4;9}$
\end{document}