Latex \today macro expanding to December 31st, 1979

233 Views Asked by At

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).

1

There are 1 best solutions below

1
Robert Hensing On BEST ANSWER

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.