blob: e87d92873c77b6829c871ee46c74e3fe171a8ec0 [file] [log] [blame]
#!/bin/sh
# Get modification time of a file or directory, or value of
# $SOURCE_DATE_EPOCH, and pretty-print it, formatted like 1 January 2000.
scriptversion=2025-06-18.21; # UTC
# Copyright (C) 1995-2025 Free Software Foundation, Inc.
# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
fi
case $1 in
'')
echo "$0: No file. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: mdate-sh [--help] [--version] FILE
Pretty-print the modification day of FILE, in the format:
1 January 1970
If the environment variable SOURCE_DATE_EPOCH is set, use its value (in
epoch-seconds) for the date instead of any FILE mtime. The FILE
argument is still required in this case, but ignored.
Report bugs to <bug-automake@gnu.org>.
GNU Automake home page: <https://www.gnu.org/software/automake/>.
General help using GNU software: <https://www.gnu.org/gethelp/>.
EOF
exit $?
;;
-v | --v*)
echo "mdate-sh (GNU Automake) $scriptversion"
exit $?
;;
esac
# Warn if more than one file given.
if test $# -ne 1; then
echo "$0: warning: multiple files given, using first: $*" >&2
fi
error ()
{
echo "$0: $1" >&2
exit 1
}
# set $month ("January") and $nummonth (1) given arg MON ("Jan").
mon_to_month ()
{
case $1 in
Jan) month=January; nummonth=1;;
Feb) month=February; nummonth=2;;
Mar) month=March; nummonth=3;;
Apr) month=April; nummonth=4;;
May) month=May; nummonth=5;;
Jun) month=June; nummonth=6;;
Jul) month=July; nummonth=7;;
Aug) month=August; nummonth=8;;
Sep) month=September; nummonth=9;;
Oct) month=October; nummonth=10;;
Nov) month=November; nummonth=11;;
Dec) month=December; nummonth=12;;
esac
}
# Prevent date giving response in another language.
LANG=C
export LANG
LC_ALL=C
export LC_ALL
LC_TIME=C
export LC_TIME
# Use UTC to get reproducible result.
TZ=UTC0
export TZ
#
# https://reproducible-builds.org/docs/source-date-epoch/
if test -n "$SOURCE_DATE_EPOCH"; then
epoch_ok=true # be optimistic
date_fmt="+%d %B %Y"
result=`date -u --date="@$SOURCE_DATE_EPOCH" "$date_fmt" 2>/dev/null`
if test -z "$result"; then
result=`date -u -r "$SOURCE_DATE_EPOCH" "$date_fmt" 2>/dev/null`
if test -z "$result"; then
# The date command on Solaris 10 and 11 doesn't support any way
# to do this. Fall back to Perl.
#
perlout=`perl -e 'print scalar gmtime($SOURCE_DATE_EPOCH)' 2>/dev/null`
# Output is, e.g., Thu Jan 1 00:00:00 1970. Split it apart,
# since we need to convert "Jan" to "January".
# (We could use cut, but surely if a system has perl, it has awk?)
day=`echo $perlout | awk '{print $3}'`
mon=`echo $perlout | awk '{print $2}'`
mon_to_month $mon # sets $month
year=`echo $perlout | awk '{print $5}'`
result="$day $month $year"
#
if test -z "$result"; then
echo "$0: warning: SOURCE_DATE_EPOCH was set, but can't convert, ignoring: $SOURCE_DATE_EPOCH" >&2
epoch_ok=false
fi
fi
fi
#
if $epoch_ok; then
# Remove leading spaces and zeros. We don't want to get into the
# various date options to control this. (Not quoting $result here
# isn't important, just another way to omit leading spaces.)
result=`echo $result | sed 's/^[ 0]*//'`
if test -z "$result"; then
echo "$0: SOURCE_DATE_EPOCH was set, but converted to empty: $SOURCE_DATE_EPOCH" >&2
epoch_ok=false
fi
fi
if $epoch_ok; then
echo $result
exit 0
else
echo "$0: SOURCE_DATE_EPOCH failed, falling back to using mtime on: $1" >&2
fi
fi
# end of SOURCE_DATE_EPOCH support, rest is about the normal case of
# using the mtime of the specified file.
#
# GNU ls changes its time format in response to the TIME_STYLE
# variable. Since we cannot assume 'unset' works, revert this
# variable to its documented default.
if test "${TIME_STYLE+set}" = set; then
TIME_STYLE=posix-long-iso
export TIME_STYLE
fi
save_arg1=$1
# Find out how to get the extended ls output of a file or directory.
if ls -L /dev/null 1>/dev/null 2>&1; then
ls_command='ls -L -l -d'
else
ls_command='ls -l -d'
fi
# Avoid user/group names that might have spaces, when possible.
if ls -n /dev/null 1>/dev/null 2>&1; then
ls_command="$ls_command -n"
fi
# A 'ls -l' line looks as follows on OS/2.
# drwxrwx--- 0 Aug 11 2001 foo
# This differs from Unix, which adds ownership information.
# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
#
# To find the date, we split the line on spaces and iterate on words
# until we find a month. This cannot work with files whose owner is a
# user named "Jan", or "Feb", etc. However, it's unlikely that '/'
# will be owned by a user whose name is a month. So we first look at
# the extended ls output of the root directory to decide how many
# words should be skipped to get the date.
# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
set x`$ls_command /`
# Find which argument is the month.
month=
command=
until test $month
do
test $# -gt 0 || error "failed parsing '$ls_command /' output"
shift
# Add another shift to the command.
command="$command shift;"
mon_to_month $1
done
test -n "$month" || error "failed parsing '$ls_command /' output"
# Get the extended ls output of the file or directory.
set dummy x`eval "$ls_command \"\\\$save_arg1\""`
# Remove all preceding arguments
eval $command
# Because of the dummy argument above, month is in $2.
#
# On a POSIX system, we should have
# $# = 5
# $1 = file size
# $2 = month
# $3 = day
# $4 = year or time
# $5 = filename
#
# On Darwin 7.7.0 and 7.6.0, we have
# $# = 4
# $1 = day
# $2 = month
# $3 = year or time
# $4 = filename
# Get the month.
mon_to_month $2
case $3 in
???*) day=$1;;
*) day=$3; shift;;
esac
# Here we have to deal with the problem that the ls output gives either
# the time of day or the year.
case $3 in
*:*) set `date`; eval year=\$$#
case $2 in
Jan) nummonthtod=1;;
Feb) nummonthtod=2;;
Mar) nummonthtod=3;;
Apr) nummonthtod=4;;
May) nummonthtod=5;;
Jun) nummonthtod=6;;
Jul) nummonthtod=7;;
Aug) nummonthtod=8;;
Sep) nummonthtod=9;;
Oct) nummonthtod=10;;
Nov) nummonthtod=11;;
Dec) nummonthtod=12;;
esac
# For the first six months of the year the time notation can also
# be used for files modified in the last year.
if (expr $nummonth \> $nummonthtod) >/dev/null;
then
year=`expr $year - 1`
fi;;
*) year=$3;;
esac
# The result.
echo $day $month $year
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%Y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End: