biblatex: extrayear only if full date is equal?

With the new \DeclareExtradate (see https://github.com/plk/biblatex/issues/540) introduced in biblatex 3.8/Biber 2.8 you only need

\DeclareExtradate{%
  \scope{
    \field{labelyear}
    \field{year}
  }
  \scope{
    \field{labelmonth}
  }
  \scope{
    \field{labelday}
  }
}

Since the date format you uses already puts the extradate field (used to be called extrayear) into the right place, we don't even need to change the date macros. One may need to modify the date printing macros in case a different output like 2017-02-27b is desired.

enter image description here


I tried to create a standalone Lua module to fix the bbl file. Sorting is not an issue here, it uses common year-month-day format. In this example we are trying to get a series from a,b,c,d to ,a,b,. We need look ahead searching otherwise we would get series of a,a,b,a. My sorting key to decide about a change in series is namehash+year+month+day, it is a combination of fields from the bbl file. The algorithm can be briefly described as follows:

  • In case two consecutive dates are not equal, comment out that first line.
  • In case they are, use a counter and modify the number (that's the second TeX parameter) in that field in both lines, e.g. to 1 and 2, 2 and 3...
  • Skip an entry on purpose if there are no year, month and day data.

Edit: We are getting a separate series for year, year+month, and year+month+day due to the used sorting key. I've fixed the fixer by adding default values, so it is working if there is no month or day data.

In our example we will get changes in the first four occurrences of extrayear from (this is the previous version, please see a revision list):

\field{extrayear}{1}
\field{extrayear}{2}
\field{extrayear}{3}
\field{extrayear}{4}

to

%\field{extrayear}{1}
\field{extrayear}{1}%2
\field{extrayear}{2}%3
%\field{extrayear}{4}

Edit: A new field is added instead of changing extrayear in a new version for safety reasons, e.g. \field{userb}{1}.

We can compare the resuls before and after use of a fixer:

mwe, comparison

Note: I think that the citations in text should be fixed somehow (hopefully at the biblatex level), it doesn't look right as we can spot AuthorA 2014 twice but for two different books. If we are using \nocite{*}, it's all right. Ulrike Fischer recommends to redefine the \cite command.

I'm using the so-called fixer (a Lua standalone library) this way:

lualatex mal-biber
biber mal-biber
luatex --luaonly mal-fixer.lua mal-biber
lualatex mal-biber

You may spot two lines in the terminal if everything is working as should be:

Mal-fixer is processing the mal-biber.bbl file...
Mal-fixer has done its assignment with 12 items!

Although I run lualatex, any LaTeX format can be used. I enclose the main TeX code and the Lua library.

%! *latex mal-biber.tex
\documentclass[fontsize=11pt,parskip=half]{scrartcl}
\pagestyle{empty}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[backend=biber,
            style=authoryear-ibid,
            datelabel=short,
            ]{biblatex}
\usepackage{etoolbox}
\usepackage{filecontents}
\def\malfile{testextra1.bib}
\begin{filecontents*}{\malfile}
@article{authorA4,
 author={AuthorA},
 title={blad},
 date={2014-03-05},
 }
@article{authorA3,
 author={AuthorA},
 title={blac},
 date={2014-03-04},
 }
@article{authorA2,
 author={AuthorA},
 title={blab},
 date={2014-03-04},
 }
@article{authorA1,
 author={AuthorA},
 title={blaa},
 date={2014-03-03},
 }
@article{gambol,
  author={Gambolputty, Johann},
  title={Titel},
  year={1970},
  }
@article{gambolb,
  author={Gambolputty, Johann},
  title={Titel},
  year={1970},
  }
@book{authorBa,
  author={AuthorB},
  title={Titel},
  date={2010-10},
  }
@book{authorBb,
  author={AuthorB},
  title={Titel},
  date={2010-10},
  }
@book{authorBc,
  author={AuthorB},
  title={Titel},
  date={2010-11},
  }
@book{authorBd,
  author={AuthorB},
  title={Titel},
  date={2010-11},
  }
@book{authorC,
  author={AuthorC},
  title={Titel},
  }
@book{authorD,
  author={AuthorD},
  title={Titel},
  date={},
  }
\end{filecontents*}
\addbibresource{\malfile}
%\ifx\relax % An updated version...
\AtEveryBibitem{% A tip for using \savefield->\restorefield by Ulrike Fischer...
\iffieldundef{extrayear}{}{%
  \clearfield{extrayear}%
  \iffieldequalstr{userb}{}{}{\savefield{userb}{\myusera}%
  \restorefield{extrayear}{\myusera}}%
  }% End of testing extrayear...
}% End of \AtEveryBibitem...
%\AtEveryCitekey{}
%\fi
\begin{document}
\nocite{*}
\ifx\relax % The \cite command must be redefined to fit those three fields...
% A tip by Ulrike Fischer: \mkbibdateshort{labelyear}{labelmonth}{labelday}
The regular paragraph\ldots\par
\cite{authorA4}\par\cite{authorA3}\par\cite{authorA2}\par\cite{authorA1}\par 
\cite{gambol}\par\cite{gambolb}\par
\cite{authorBa}\par\cite{authorBb}\par\cite{authorBc}\par\cite{authorBd}\par
\cite{authorC}\par\cite{authorD}\par
\fi
\printbibliography
\end{document}

And the library is this file:

-- I am a mal-fixer.lua file, version 3 from 2014-04-04...
-- I am fixing extrayear in the bbl file...

---- Common usage: ----
-- lualatex mal-biber
-- biber mal-biber
-- luatex --luaonly mal-fixer.lua mal-biber
-- lualatex mal-biber

local name=arg[1] -- Get me a name from the command line...
if string.sub(name,-4)~=".bbl" then name=name..".bbl" end -- Add me an extension if I don't have one
--print(name) -- Show me the name of the file...
--do return end -- Quick exit of Lua...
print("\nMal-fixer is processing the "..name.." file...") -- Information sent to the terminal...

local myfile=io.open(name,"r") -- Read the file...
local content=myfile:lines() --("*a")

local mybackup=io.open(name.."-backup","w") -- Open me as a backup file...

local saved={} -- Storage of all data...
local mal=0 -- A counter of \entry commands...

for oneline in content do -- The main cycle over lines...
mybackup:write(oneline.."\n") -- Backup of a single line...

-- If a line contains \entry, use counter mal +1...
malvalue=string.find(oneline,"\\entry")
if malvalue~=nil then
  mal=mal+1
  saved[mal]={}
  -- initial setting...
  saved[mal][1]="" -- In general, there is no need for namehash to be initialized, it is always there, but just to be sure...
  saved[mal][2]=""
  saved[mal][3]=""
  saved[mal][4]=""
  --print(oneline)
end

-- Search for these items in a line...
maltran={"namehash", "year", "month", "day"}
for k,v in pairs(maltran) do
searchme=".-{"..v.."}{(.-)}"
malvalue=string.find(oneline,searchme) --,"%1"
--print("MY LINE: "..oneline)
if malvalue~=nil then 
  --print(malvalue) 
  value=string.gsub(oneline,searchme,"%1")
  --print(value)
  saved[mal][k]=value -- Add their TeX value to my storage...
end --of if malvalue
end --of for k,v

end --of for oneline
--print(mal)

-- A creation of long hash...
for k=1,#saved do
  saved[k][5]=saved[k][1]..saved[k][2]..saved[k][3]..saved[k][4]
  saved[k][6]=0 -- the default value is zero, comment out that extrayear
  --print(saved[k][5])
end

-- The comparison of two citations...
maltemp=1
for k=1,#saved-1 do
  if saved[k][5]==saved[k+1][5] then 
--print("they are equal") -- 1 2, 2 3, 3 4, ... 
saved[k][6]=maltemp
maltemp=maltemp+1
saved[k+1][6]=maltemp
  else 
--print("they are not the same") -- Don't change anything...
maltemp=1 -- just set counter to one
  end -- of if saved
end --of for k

-- For checking purposes only: list me the values...
-- for k=1,#saved do
-- print(saved[k][6])
-- end --of for k

-- Close those two files and open them again read and write mode in reverse...
myfile:close()
mybackup:close()

myfile=io.open(name,"w") -- From reading to writing...
mybackup=io.open(name.."-backup","r") -- From writing to reading...
content=mybackup:lines()

maltemp=0
for oneline in content do
malvalue=string.find(oneline,"\\entry") -- {extrayear} was here
malpercent=string.find(oneline,"%%")

if malvalue~=nil and malpercent==nil then -- Skip me if it is already updated (it occures only when there are multiple runs of mal-fixer.lua)...
  maltemp=maltemp+1 -- n-th occurence in the file

if saved[maltemp][2]..saved[maltemp][3]..saved[maltemp][4]=="" then -- Neither year nor month nor day is stored in the bibliography entry, then do absolutly nothing...
else

if saved[maltemp][6]==0 then -- Does this date stand alone? Yes, it does.
  -- This is an old version changing extrayear field...
  -- oneline=string.gsub(oneline,"(.-)(\\.-)","%1%%%2") -- Comment out this line...
  oneline=oneline.."\n      \\field{userb}{}"
else -- No, it doesn't.
  -- This is an old version...
  -- oneline=string.gsub(oneline,"(.-year}{)(.-)(}.-)","%1"..tostring(saved[maltemp][6]).."%3%%%2") -- Change the value inside the TeX parameter...
  oneline=oneline.."\n      \\field{userb}{"..tostring(saved[maltemp][6]).."}"
end --of saved

end --of saved[maltemp] year+month+day

end --of if malvalue

myfile:write(oneline.."\n")
end --of for oneline (second cycle)
-- print(maltemp)

-- Close those two files again...
myfile:close()
mybackup:close()

-- Send a note to the terminal and exit the code...
local maltextbonus=""
if maltemp>1 then maltextbonus="s" end
print("Mal-fixer has done its assignment with "..tostring(mal).." item"..maltextbonus.."!")
--

I hope someone will have a better answer, but meanwhile I just want to point out that you can mistreat the year field by putting more there, and biber won't complain:

@article{authorA1,
 author={authorA},
 title={blaa},
 year={03.03.2014}
 }

@article{authorA2,
 author={authorA},
 title={blab},
 year={04.03.2014}
 }


@article{authorA3,
 author={authorA},
 title={blac},
 year={04.03.2014}
 }

@article{authorA4,
 author={authorA},
 title={blad},
 year={05.03.2014}
 }

Tags:

Biblatex

Biber