With latex installed through the nix package manager (on nixos), \today always expands to December 31st, 1979. How do I get this to return the correct date?
MWE Create a directory and add the mwe.tex and flake.nix (based off https://flyx.org/nix-flakes-latex/).
-- mwe.tex --
\documentclass[11pt]{article}
\title{}
\date{\today}
\begin{document}
\maketitle
\end{document}
-- mwe.tex ends here --
-- flake.nix --
{
description = "MWE for reproducing \\today macro problem";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
tex = pkgs.texlive.combine {
inherit (pkgs.texlive) scheme-minimal latex-bin latexmk;
};
in rec {
packages = {
document = pkgs.stdenvNoCC.mkDerivation rec {
name = "mwe";
src = self;
buildInputs = [ pkgs.coreutils tex ];
phases = [ "unpackPhase" "buildPhase" "installPhase" ];
buildPhase = ''
export PATH="${pkgs.lib.makeBinPath buildInputs}";
mkdir -p .cache/texmf-var
env TEXMFHOME=.cache TEXMFVAR=.cache/texmf-var \
latexmk -pdf -lualatex mwe.tex
'';
installPhase = ''
mkdir -p $out
cp mwe.pdf $out/
'';
};
};
defaultPackage = packages.document;
});
}
-- flake.nix ends here --
Then run nix build "."
in the new directory. The results should be a pdf containing December 31, 1979 (or when I just ran this I actually got January 1, 1980).
WARNING: Use a hardcoded date if you release your document close to a deadline.
The date will most likely be based on UTC, so if your document is meant for a local context, this could lead to a small surprise when committing during the start or end of the day, depending on time zone.
UPDATE (thanks @voidee123)
latex uses the environment variable SOURCE_DATE_EPOCH to determine the date.
This leads to a simpler solution
{
description = "MWE for reproducing \\today macro problem";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
tex = pkgs.texlive.combine {
inherit (pkgs.texlive) scheme-minimal latex-bin latexmk;
};
in rec {
packages = {
inherit tex;
document = pkgs.stdenvNoCC.mkDerivation rec {
name = "mwe";
src = self;
nativeBuildInputs = [ pkgs.coreutils pkgs.libfaketime tex ];
phases = [ "unpackPhase" "buildPhase" "installPhase" ];
SOURCE_DATE_EPOCH = self.sourceInfo.lastModified;
buildPhase = ''
mkdir -p .cache/texmf-var
env TEXMFHOME=.cache TEXMFVAR=.cache/texmf-var \
latexmk -pdf -lualatex mwe.tex
'';
installPhase = ''
mkdir -p $out
cp mwe.pdf $out/
'';
};
};
defaultPackage = packages.document;
});
}
Original answer for context
Nix tries its best to make builds reproducible. This includes setting the date, because too many tools leave a date in their outputs. In other words, Nix is a tool for making builds functional. In a mathematical function, time would be an input or parameter. You can do the same here, or simply hardcode the date you want to release the document.
If it is a living document and it is committed to git, you can use of the flake metadata (making the metadata an input to your "function"). You can write it to a file in the build during buildPhase
:
# format: YYYYMMDDHHMMSS
echo ${self.sourceInfo.lastModifiedDate} >date.txt
# format: YYYY-MM-DD
echo ${
nixpkgs.lib.substring 0 4 self.sourceInfo.lastModifiedDate
+ "-" +
nixpkgs.lib.substring 4 2 self.sourceInfo.lastModifiedDate
+ "-" +
nixpkgs.lib.substring 6 2 self.sourceInfo.lastModifiedDate
} >date.txt
or
# format: unix timestamp
echo ${self.sourceInfo.lastModified} >date.txt
You can then use \input{date.txt}
where you need the date.