1

I'm (mis)using biblatex to treat the degrees and experience of a plant-enthusiast friend of mine as bib entries of type @MISC.

It turns out that my friend is not quite finished his PhD. He wishes to communicate this in his list of degrees by using the elegantly long dash produced by --- and by appending this to the starting year of his in-progress degree in the year field of the bib entry. This seems to display rather nicely.

The trouble is, the list doesn't sort properly, in fact the following warning message is issued by biber:

WARN - year field '2015---' in entry 'PhD' is not an integer - this will probably not sort properly.

I prepared the following mwe to demonstrate this issue:

\NeedsTeXFormat{LaTeX2e}
\documentclass[12pt]{article}

\usepackage[backend=biber,%
isbn=false,%
style=numeric,%
sorting=ydnt,%
giveninits=true,% initials of first names
maxbibnames=20,%
defernumbers,%
labeldateparts,% for academic cv
locallabelwidth% for academic cv
]{biblatex} 

\usepackage{filecontents}

\begin{filecontents}{\jobname.bib}
@Misc{BSc,
  title = {B.Sc. in Observing the Natural World},
  year  = {2010},
  note  = {The University, Place},
}

@Misc{PhD,
  title = {Ph.D. candidate, Botany and Plant Science},
  year  = {2015---},
  note  = {The Other University, The Other Place},
}

@Misc{MSc,
  title = {M.Sc. in Epidemiology},
  year  = {2012},
  note  = {The University, Place},
}
\end{filecontents}


\begin{filecontents}{cvsectionnum.tex}
% define a bibenvironment for an numbered bib entry
\defbibenvironment{bibenvcvsectionnum}%
{\list%
{\printtext[labelnumberwidth]{%
\printfield{labelprefix}%
\printfield{labelnumber}}}%
{\setlength{\leftmargin}{\bibhang}%
\setlength{\itemsep}{\bibitemsep}%
\setlength{\parsep}{\bibparsep}}}%
{\endlist}%
{\item}%

% cvsectionnum
\newcommand\cvsectionnum[3]{%
\section*{#1}%
\begin{refsection}[#2]%
\nocite{*}%
\printbibliography[heading=none,env=bibenvcvsectionnum,#3]%
\end{refsection}%
}%
\end{filecontents}


\begin{filecontents}{reverse_order_bib_entry_numbering.tex}
\AtDataInput{%
\csnumgdef{entrycount:\therefsection}{%
\csuse{entrycount:\therefsection}+1}}%
%
\DeclareFieldFormat{labelnumber}{\mkbibdesc{#1}}%
\newrobustcmd*{\mkbibdesc}[1]{%
\number\numexpr\csuse{entrycount:\therefsection}+1-#1\relax}%
\end{filecontents}


\addbibresource{\jobname.bib}%


% declare section names
\def\sectiona{Publications}%


% definition of `cvsectionnum'
\input{cvsectionnum.tex}

% reverse order numbering
\input{reverse_order_bib_entry_numbering.tex}

\begin{document}

% Publications
\cvsectionnum{\sectiona}{\jobname.bib}{}%

\end{document}

I don't think this is so much an issue because, my friend and I, we're clearly violating the fact that the year field should be an integer; and we're passing it a string (2015---).

That said, perhaps someone in the community has some clever ideas on how to work around.

This is what the output looks like:

enter image description here

The ongoing activity which is the PhD should appear first from top to bottom and should have the label 3, ideally.

Actually, here is my friend's preferred way to represent the education items:

\NeedsTeXFormat{LaTeX2e}
\documentclass[12pt]{article}

\usepackage[backend=biber,%
isbn=false,%
style=numeric,%
sorting=ydnt,%
giveninits=true,% initials of first names
maxbibnames=20,%
defernumbers,%
labeldateparts,% for academic cv
locallabelwidth% for academic cv
]{biblatex} 

\usepackage{filecontents}

\begin{filecontents}{\jobname.bib}
@Misc{BSc,
  title = {B.Sc. in Observing the Natural World},
  year  = {2010},
  note  = {The University, Place},
}

@Misc{PhD,
  title = {Ph.D. candidate, Botany and Plant Science},
  year  = {2015---},
  note  = {The Other University, The Other Place},
}

@Misc{MSc,
  title = {M.Sc. in Epidemiology},
  year  = {2012},
  note  = {The University, Place},
}
\end{filecontents}


\begin{filecontents}{cvsectionyearlabelkeywords.tex}
% cvsectionyearlabelkeywords
\newcommand\cvsectionyearlabelkeywords[3]
{%
\section*{#1}%
%\changedateformat{label}{long}% just the year
\begin{refsection}[#2]%
\nocite{*}%
\printbibliography[heading=none, env=bibenvcvsectionyearlabel,#3]%
\end{refsection}%
}%


% define a custom bib environment
\defbibenvironment{bibenvcvsectionyearlabel}
{\list
     {\printtext{\printlabeldate}}%{\printtext[parens]{\printlabeldate}}
     {\setlength{\labelwidth}{\labeldatewidth}%
      \setlength{\leftmargin}{\labelwidth}%
      \setlength{\labelsep}{\biblabelsep}%
      \addtolength{\leftmargin}{\labelsep}%
      \setlength{\itemsep}{\bibitemsep}%
      \setlength{\parsep}{\bibparsep}}%
      \renewcommand*{\makelabel}[1]{##1\hss}}
  {\endlist}
  {\item}


\renewbibmacro*{date}{%
  \ifboolexpr{
    test {\iflabeldateisdate}
    and
    not test {\ifdateshavedifferentprecision{label}{}}
  }
    {}
    {\printdate}}



\renewbibmacro*{issue+date}{%
  \ifboolexpr{
    test {\iflabeldateisdate}
    and
    not test {\ifdateshavedifferentprecision{label}{}}
    and
    test {\iffieldundef{issue}}
  }
    {}
    {\printtext{%{\printtext[parens]{
       \printfield{issue}%
       \setunit*{\addspace}%
       \printdate}}%
  \newunit}

\makeatletter
\newlength{\labeldatewidth}
\newlength{\locallabeldatewidth}

\preto\blx@bbl@labeldate
  {\blx@getlabeldata
   \blx@setlabwidth{\labeldatewidth}{\printtext{\printlabeldate}}}%\blx@setlabwidth{\labeldatewidth}{\printtext[parens]{\printlabeldate}}}
  {}{}
\apptocmd\blx@labelwidth@resetlocal{\locallabeldatewidth0pt\relax}{}{}
\apptocmd\blx@labelwidth@settolocal{\labeldatewidth\locallabeldatewidth\relax}{}{}

\def\blx@lengthitem#1{%
  \blx@ifdata{#1}
    {\begingroup
     \blx@getdata{#1}%
     \blx@bibcheck
     \iftoggle{blx@skipentry}{}{%
       \iftoggle{blx@labelnumber}
         {\blx@bbl@locallabelnumberwidth}
         {}%
       \iftoggle{blx@labelalpha}
         {\blx@bbl@locallabelalphawidth}
         {}%
       \nottoggle{blx@skipbiblist}
         {\blx@bbl@locallabelfields}
         {}
       \blx@setlabwidth{\locallabeldatewidth}{\printtext{\printlabeldate}}}%\blx@setlabwidth{\locallabeldatewidth}{\printtext[parens]{\printlabeldate}}} 
     \endgroup}
    {}}

\newrobustcmd*{\changedateformat}[2]{%
  \csdef{blx@dateformat@#1date}{#2}%
  \protected\csdef{blx@imc@print#1date}{\csuse{mkdaterange#2}{#1}}%
  \protected\csdef{blx@imc@print#1dateextra}{\csuse{mkdaterange#2extra}{#1}}}
\makeatletter
\end{filecontents}


\begin{filecontents}{reverse_order_bib_entry_numbering.tex}
\AtDataInput{%
\csnumgdef{entrycount:\therefsection}{%
\csuse{entrycount:\therefsection}+1}}%
%
\DeclareFieldFormat{labelnumber}{\mkbibdesc{#1}}%
\newrobustcmd*{\mkbibdesc}[1]{%
\number\numexpr\csuse{entrycount:\therefsection}+1-#1\relax}%
\end{filecontents}


\addbibresource{\jobname.bib}%


% declare section names
\def\sectiona{Education}%


% definition of `cvsectionnum'
\input{cvsectionyearlabelkeywords.tex}

% reverse order numbering
\input{reverse_order_bib_entry_numbering.tex}


\begin{document}

% Education
\cvsectionyearlabelkeywords{\sectiona}{\jobname.bib}{}%

\end{document}

Which looks like:

enter image description here

Again, the order is broken and does not effectively communicate my pal's eclectic formation.

3

There are at least two possible solutions.

Use date and ISO input

While the year field only accepts integer years, the (now preferred) date field accepts a whole range of ISO 8601 date formats. Amongst other things date accepts date ranges, even open-ended ones. In ISO 8601 date ranges use / as separator, since - is taken as the separator between year, month and day, so the ISO 8601 input would be

@Misc{PhD,
  title = {Ph.D. candidate, Botany and Plant Science},
  date  = {2015/},
  note  = {The Other University, The Other Place},
}

Use sortyear

If you have a non-integer year field, you can still give Biber/BibTeX a chance to sort it correctly by adding a integer-valued sortyear, for example

@Misc{PhD,
  title    = {Ph.D. candidate, Botany and Plant Science},
  year     = {2015---},
  sortyear = {2015},
  note     = {The Other University, The Other Place},
}

MWE using date. By default the range separator is an en-dash and not an em-dash, but you can get an em-dash after the year with \renewrobustcmd*{\bibdaterangesep}{\textemdash}.

\NeedsTeXFormat{LaTeX2e}
\documentclass[12pt]{article}

\usepackage[backend=biber,%
isbn=false,%
style=numeric,%
sorting=ydnt,%
giveninits=true,% initials of first names
maxbibnames=20,%
defernumbers,%
labeldateparts,% for academic cv
locallabelwidth% for academic cv
]{biblatex} 


\begin{filecontents}{\jobname.bib}
@Misc{BSc,
  title = {B.Sc. in Observing the Natural World},
  year  = {2010},
  note  = {The University, Place},
}
@Misc{PhD,
  title = {Ph.D. candidate, Botany and Plant Science},
  date  = {2015/},
  note  = {The Other University, The Other Place},
}
@Misc{MSc,
  title = {M.Sc. in Epidemiology},
  year  = {2012},
  note  = {The University, Place},
}
\end{filecontents}


\begin{filecontents}{cvsectionyearlabelkeywords.tex}
% cvsectionyearlabelkeywords
\newcommand\cvsectionyearlabelkeywords[3]
  {%
   \section*{#1}%
    %\changedateformat{label}{long}% just the year
    \begin{refsection}[#2]%
      \nocite{*}%
      \printbibliography[heading=none, env=bibenvcvsectionyearlabel,#3]%
    \end{refsection}%
  }%


% define a custom bib environment
\defbibenvironment{bibenvcvsectionyearlabel}
  {\list
     {\printtext{\printlabeldate}}%{\printtext[parens]{\printlabeldate}}
     {\setlength{\labelwidth}{\labeldatewidth}%
      \setlength{\leftmargin}{\labelwidth}%
      \setlength{\labelsep}{\biblabelsep}%
      \addtolength{\leftmargin}{\labelsep}%
      \setlength{\itemsep}{\bibitemsep}%
      \setlength{\parsep}{\bibparsep}}%
      \renewcommand*{\makelabel}[1]{##1\hss}}
  {\endlist}
  {\item}

\renewrobustcmd*{\bibdaterangesep}{\textemdash}

\renewbibmacro*{date}{%
  \ifboolexpr{
    test {\iflabeldateisdate}
    and
    not test {\ifdateshavedifferentprecision{label}{}}
  }
    {}
    {\printdate}}



\renewbibmacro*{issue+date}{%
  \ifboolexpr{
    test {\iflabeldateisdate}
    and
    not test {\ifdateshavedifferentprecision{label}{}}
    and
    test {\iffieldundef{issue}}
  }
    {}
    {\printtext{%{\printtext[parens]{
       \printfield{issue}%
       \setunit*{\addspace}%
       \printdate}}%
  \newunit}

\makeatletter
\newlength{\labeldatewidth}
\newlength{\locallabeldatewidth}

\preto\blx@bbl@labeldate
  {\blx@getlabeldata
   \blx@setlabwidth{\labeldatewidth}{\printtext{\printlabeldate}}}%\blx@setlabwidth{\labeldatewidth}{\printtext[parens]{\printlabeldate}}}
  {}{}
\apptocmd\blx@labelwidth@resetlocal{\locallabeldatewidth0pt\relax}{}{}
\apptocmd\blx@labelwidth@settolocal{\labeldatewidth\locallabeldatewidth\relax}{}{}

\def\blx@lengthitem#1{%
  \blx@ifdata{#1}
    {\begingroup
     \blx@getdata{#1}%
     \blx@bibcheck
     \iftoggle{blx@skipentry}{}{%
       \iftoggle{blx@labelnumber}
         {\blx@bbl@locallabelnumberwidth}
         {}%
       \iftoggle{blx@labelalpha}
         {\blx@bbl@locallabelalphawidth}
         {}%
       \nottoggle{blx@skipbiblist}
         {\blx@bbl@locallabelfields}
         {}
       \blx@setlabwidth{\locallabeldatewidth}{\printtext{\printlabeldate}}}%\blx@setlabwidth{\locallabeldatewidth}{\printtext[parens]{\printlabeldate}}} 
     \endgroup}
    {}}

\newrobustcmd*{\changedateformat}[2]{%
  \csdef{blx@dateformat@#1date}{#2}%
  \protected\csdef{blx@imc@print#1date}{\csuse{mkdaterange#2}{#1}}%
  \protected\csdef{blx@imc@print#1dateextra}{\csuse{mkdaterange#2extra}{#1}}}
\makeatletter
\end{filecontents}


\begin{filecontents}{reverse_order_bib_entry_numbering.tex}
\AtDataInput{%
  \csnumgdef{entrycount:\therefsection}{%
    \csuse{entrycount:\therefsection}+1}}%
%
\DeclareFieldFormat{labelnumber}{\mkbibdesc{#1}}%
\newrobustcmd*{\mkbibdesc}[1]{%
  \number\numexpr\csuse{entrycount:\therefsection}+1-#1\relax}%
\end{filecontents}


\addbibresource{\jobname.bib}%

\def\sectiona{Education}%


\input{cvsectionyearlabelkeywords.tex}
\input{reverse_order_bib_entry_numbering.tex}

\begin{document}
\cvsectionyearlabelkeywords{\sectiona}{\jobname.bib}{}%
\end{document}

2015— Ph.D. candidate, Botany and Plant Science. The Other University, The Other Place.//2012 M.Sc. in Epidemiology. The University, Place.//2010 B.Sc. in Observing the Natural World. The University, Place.

  • Brilliant. One best case solution and also one that lends itself to quick implementation and backward compatibility (e.g. if the bib database was large). I think the isodate option is ideal because it seems I have another sorting issue (could be wrong but did check one example) where both year and month are not considered when invoking the ydnt option. Any comments appreciated. – John Chris Oct 26 '19 at 15:24
  • 1
    @JohnChris ydnt only takes the year into account. If you want to sort by month, you need to define a new sorting format. See tex.stackexchange.com/q/140561/35864 and tex.stackexchange.com/q/46868/35864 – moewe Oct 27 '19 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.