1

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

Robert Hensing
  • 6,708
  • 18
  • 23
voidee123
  • 13
  • 2

1 Answers1

1

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.

Robert Hensing
  • 6,708
  • 18
  • 23
  • I've also found (on the page I linked above) latex uses the enviornment variable `SOURCE_DATE_EPOCH` to determine the date. So passing latexmk that variable can be used instead of date.txt. I.e. ` SOURCE_DATE_EPOCH=${self.lastModified} latexmk ...`. – voidee123 Dec 19 '21 at 03:43