Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
CalVer: Calendar Versioning (calver.org)
194 points by tosh on Jan 6, 2020 | hide | past | favorite | 99 comments


This comes crashing down in a nice mudslide the exact moment you start maintaining an older stable release for fixes while also progressing on a newer version. If anything, date codes are useful as later version number component, e.g. 4.1.0.191220.

Also, the "When to use" section is getting things quite wrong:

  Does your project feature a large or constantly-changing scope?
    Large systems and frameworks, like Ubuntu and Twisted.
    Amorphous sets of utilities, like Boltons.
Wrong question - relevant is: "is your project the top end of the dependency chain?"

  Is your project time-sensitive in any way? Do other external changes drive new project releases?
    Business requirements, such as Ubuntu's focus on support schedules.
    Security updates, such as certifi's need to update certificates.
And both of these are actually made much harder by calendaric versioning. Administrators are already reluctant to update software for fear of breaking things. SemVer gives extremely useful information here to establish how "dangerous" and update might be. With date code versions, the admin is forced to dig through change logs, which costs time they probably don't have, so they'll just not update.


> SemVer gives extremely useful information here to establish how "dangerous" and update might be.

I'm doubtful about how useful the information SemVer gives really is. Someone can make massive changes to a package, rewrite half of it from scratch, add huge new features, completely redesign how parts of it are implemented, but if they don't making any breaking API changes the first version segment doesn't increment. On the other hand, someone removes some obscure feature which nobody ever used anyway, and that causes the first version segment to increment. The administrator should be much more worried about the first change than the second, but SemVer misleads them into being more worried about the second than the first.


SemVer is about the public API, it says nothing about test-coverage, internal changes or transient dependencies.

The point of SemVer is to answer "if I trust the authors of this library to be as good or better than me at writing libraries, is it safe to upgrade?". The moment you don't trust the authors of the library to be as good or better than you it sorta breaks apart as a covenant, but it will still show the intent of the author.

So SemVer has problems, but CalVer just shows "I tagged a release at a date".

IMO badly practiced SemVer is better than perfect CalVer simply because I can open an issue of fix something that was broken because of SemVer, but with CalVer I need to live with any breakages regardless of if they were intentional or not.


Why? The version number is determined by the original release date, and after that it's just a normal version number. Pretty sure the Teradata library linked does basically that. Python's manylinux standard is another example.

The whole point of CalVer as an alternative is that SemVer has sold folks a bill of goods with regard to software maintenance. Perpetuating the idea that people can blindly update will always create problems.

More discussion here: https://sedimental.org/designing_a_version.html


> Why?

Why what? (I seriously don't understand what argument you're trying to make in your first paragraph.)

> [...] SemVer has sold folks a bill of goods with regard to software maintenance. Perpetuating the idea that people can blindly update will always create problems.

You're forgetting to ask the question whether this bill of goods is desirable. Considering the environment we have today (frequent security updates, huge dependency chains, interconnected systems), I'd say it's not just desirable but straight up necessary. People should be able to blindly update. They need to be able to, because users are not developers and updates need to be made as accessible as possible in order to propagate and proliferate as quickly as possible.

What we need is better testing and release engineering to get SemVer right, not defining the problem away by ditching a layer of usability.


I was only asking why you say it comes crashing down, when the link cites multiple cases of successful parallel version maintenance with a version that is at least partially calendar-based.

As far as usability, time is a dimension no developer can escape. We develop software on a schedule and we deprecate it on a schedule. CalVer is tremendously semantic at that higher level. The semantics SemVer clings to suffer even under ecosystems which have mandated their use (go, node). The effect has been an over-granularization of APIs themselves.

I'm fine with agreeing to disagree for now. I'm also fine with the case that CalVer is not for everyone and everything. I'll leave it with this, a post seems to articulate a lot of your concerns: https://caremad.io/posts/2016/02/versioning-software/

It was written in 2016 by Donald Stufft, a maintainer of pip. Today, pip has been CalVer for a while and I'm not sure anyone has looked back. Try it sometime, and you might find the same. :)


The fix to it coming crashing down seems to be to append another version number, at which point the date code becomes kind of a branch indicator.

Now you have a choice of either incrementing the date code liberally for small releases (e.g. Twisted), or keeping it sticky until you make a major change (e.g. Teradata.)

If you do the former, you're depriving the user (or chain-up developer) of information on how big a particular change was. It might be 20190322 to 20190411 but you merged a huge rewrite. Or it's 20180107 to 20190929 and it's just some fixes. You might as well give your releases alphabetically increasing codenames, same information content there.

On the other hand if you keep it sticky until you make a major change, you're back to making a call whether some change is "major" or not. You might as well use SemVer. If anything, a date code in front of the version number becomes misleading since if you reach a reasonably stable API it'll start getting weirdly old and confuse users.

I also find it funny (and somewhat disingenious) that you assume I never tried calendaric versioning. I use (or suggest) it whenever some project starts or otherwise (e.g. rewrite) goes through an instability period. This generally means version numbers like "0.20190811". When the instability period has passed, it moves to e.g. "1.0" and sticks with SemVer from there. If we start rewriting on top of 2.3, the version number might temporarily be e.g. "2.99.20200105". Exact numbers (and components/dot count) depends on the specific situation.

It's hopefully obvious that all of these versions are something I'd call "alpha" or "internal consumption". (Also means my brain has learned prejudice to distrust any version number with a date code.)

[Edited] P.S.: developers can't escape time, but code can. I recently dug up a project I last touched in 2007, and you know what? I don't even get compiler warnings. It just works. (It's obviously written in a language & ecosystem that affords this possibility — not all of them do.)


Why not use two date codes, the release date and the update date?


For starters, that's a pretty long version number, making it difficult to see at a glance what the relation is. One date (or two for comparing) is something humans are trained to handle, two dates (or four!) not so much.

Also, now you just have SemVer with really large version numbers.


The release date portion may be abbreviated (assuming no more than one major release per month).

Released 2020-04-05, updated 2020-10-15.

Version: 2004.201015

I'm not in love with that, but that's how I'd assume it'd work.


I find calendar versioning virtually useless. It reveals the freshness of one's project over much more important information such as maturity, as revealed by semantic versioning.

Imagine researching some libraries and having to decide over which one to use, say LibA v2020.01.06 vs LibB 2019.12.31. These versions tell you nothing about the projects except their release dates.

On the other hand, semantic versioning (when not abused) – say LibA v3.0.1 vs LibB 1.0.0 – reveals something useful, such as, that LibA has undergone three major revisions, so perhaps it is much more mature than LibB.

Perhaps the calendar versioning works well with already mature and famous projects – e.g. Ubuntu 18.04, etc – but for smaller projects I don't think it's such a good idea.

Comment v1.0.4-20jan06


Not sure if you should rely on SemVer for maturity estimates either, though. I guess it can be one signal, but I wouldn't say a very useful one.


If anything, calendar version is superior here because you can tell when it was updated (and if it follows modern conventions, techniques, etc.)


yeah is 1.7 a very stable 1.x or a very immature 2.x? what is 0.7 then? and 2.0?

can't answer one and the other consistently.

it's great for compatibility level, and that's that.


Indeed, React got to version 0.14.x before the major number became 15 after a total of three years since the first public release.


what would be a more reliable way to know?


Look at the following:

- Number of commits.

- Number of open issues.

- Number of closed issues.

- How they respond to issues.

- Are the commit messages descriptive?

- Is the codebase a mess or does it look reasonable?


> say LibA v3.0.1 vs LibB 1.0.0 – reveals something useful, such as, that LibA has undergone three major revisions, so perhaps it is much more mature than LibB.

It can also mean that LibA messed up their API design twice and had to break BC twice while LibB worked diligently to provide a design that nailed it at first try or spent years in 0.XX territory and only called it stable when they were certain it's stable.

I don't consider SemVer useful to compare the maturity of software components. It's not a statement about that. It's useful to get a grip on how hard it's likely to be to go from one version to the next one.


A short list of SemVer's failures to communicate project maturity: https://0ver.org/


It's not a good fit for libraries but it's great for applications.

edit: I'm also a huge fan because unlike semver it can be easily generated in a CD pipeline.


Everything is a library to someone.


High major numbers with semver is a "stay far far away" signal for me; each major increment is a non-backwards compatible change.


Major numbers don't always match actual number of major releases. For example Java skipped from 1.4.x to 5.0.0 and React from 0.14.x to 15.0.0.


Every statistic is meaningless insofar as the statistic might be made up.


Anytime I see calendar versioning I assume one or more of the following are true about the project/package:

- it is poorly maintained

- the authors are being lazy

- it's some kind of unofficial patch or build

- marketing has taken over

- nostalgia (for Windows 95?) or imitating turn of the century project marketing

I don't think there's a good reason to ever deviate from the simple [$MAJOR_CHANGES].[$NEW_FEATURES].[$PATCH]. I don't even think it needs to be formally specified (looking at you SemVer). Simple 3-tuple versioning is almost universally understood. Why fix what isn't broken?


I'm using similar versioning for pre-build packages, but it's extended with commit information to 1:1 mapping to the source tree:

  local date=$(git log -1 --format="%cd" --date=short | sed s/-//g)
  local count=$(git rev-list --count HEAD)
  local commit=$(git rev-parse --short HEAD)
  echo "$date.${count}_$commit"
Example result:

  20191121.68_84f90ff
It provides user about general information about when program was updated along with specific information for developer for bug reporting. Also, it allows intraday releases.


You can also just use "git describe" to get more or less the exact same information, which is useful for development releases that are untagged when using versioning schemes like semantic versioning.


It helps to have the versioning ordered correctly, so I'd zero-pad the ${count} variable, like so:

    printf "%s.%03d_%s\n" $date $count $commit


For several packages I maintain, the version number is just $(git rev-list --count HEAD). One monotonically increasing number, nothing else.

(This is for software that does not do updates to old releases. If you do updates to old releases, you need an additional version number component for that.)


In build2 we do something similar for snapshot versioning between releases by incorporating the date and commit id into the pre-release component of semver. The result is a unique, properly ordered version for every commit in a project (we call it "continuous versioning"). If anyone is interested, here are the details: https://build2.org/build2/doc/build2-build-system-manual.xht...


FYI, using `local foo=$(some-command)` does not actually make the variable local.

    main() {
      local count=$(git rev-list --count HEAD)
      echo $count
      foo
    }
    
    
    foo() {
      echo $count
    }
    
    main

prints:

2282 2282


Sure it does, that’s just how locals work (in bash and similar). Try printing it after `main` with and then without `local`.


Ah my mistake

Anyways there are some more subtle caveats discussed in this blogpost I was trying to remember:

https://jmmv.dev/2018/03/shell-readability-local.html


I thought this was a new team calendar that was version controlled when I first read the headline. And now I want that.


I also wish all of my data was version controlled, which is why when I created EteSync[1] I made sure to include a full change history. Check it out, I think it's exactly what you're looking for, and it's fully open source, so you can host in on-site if your company requires that.

https://www.etesync.com


Can that do shared calendars? (I know that's technically challenging with ETE encryption). If it does, I will drop my self-hosted davical for it in a heartbeat.


I found this in the FAQ:

If I want to share a calendar with my spouse, do I need to get two subscriptions? No. You can just create a normal subscription for yourself, and an "Associate" subscription for your spouse. Then share the calendar with the second account, and that's it. However, Associate accounts can't create their own calendars. So in order to have a personal calendar (that you can't see), your spouse will have to get a normal subscription too.


Yeah, it does. You just need to manually verify each member you add to make sure they are trusted (or alternatively just YOLO).


I will take a look! I'm looking to further distance myself from Google and such this year, so this is very timely.


I had exactly the same thought, it's kind of an interesting idea. I'm not 100% sure what the usefulness is though.


I suppose it depends on how much content you put in your calendars, but I agreed with you on the usefulness, at first.

Then I thought about how meeting requests are basically PRs. How how easy it could be to create shared calendars using submodules and such.


One use case for this that comes to mind is for patching multiple major versions with a particular fix.

For example, you might release a hotfix patch today that fixes a bug in all major versions of your software. Using calendar versioning as a patch number would give something like

- 3.4.20200106

- 2.1.20200106

- 1.5.20200106

making it very easy to tell whether a particular version includes todays fix or not.


A good 30 minute podcast discussing this topic is Episode #164 "Meaningless Version Numbers" of Under The Radar podcast with Marco Arment and _David Smith.

During this episode Marco explains his decision to switch to YYYY.MINOR.MICRO scheme for Overcast, his podcast player.

https://www.relay.fm/radar/164


> YY - Short year - 6, 16, 106

> [...]

> Note that traditional, incremented version numbers are 0-based, whereas date segments are 1-based, and the short and zero-padded years are relative to the year 2000.

Y3K here we come!


You don't need to wait for Y3k. 21xx is enough to cause duplication.

There is software still running from over 50 years ago. I'd imagine new releases have come out. But, this may be a legit problem some day.


The upside being that releasing a new version with a different version scheme isn't a time-sensitive task, the old version isn't going to stop working just because the new version number wouldn't be valid.


Changing versioning schemes comes with its own set of problems. There is rather famously no "Windows 9" because enough people detected Windows 95/98 with the equivalent of a regex looking for "Windows 9*" that Microsoft thought it might be a problem.


My point isn't that it has no downsides, my point is that it would be a far less pressing issue than Y2K was.


This specification defines `YY` and `0Y` as switching to 3 digits for 21xx (i.e. it outputs it as 1xx).


I find this absolutely useless for libraries.

For things like Ubuntu yes, it makes sense because you wouldn't just run a command to upgrade your os.

However, your code you usually has a bunch of libraries that depends on. When I upgrade a library I don't care when the new version came out, all I care is that doesn't have breaking changes.

With semver I can get this information at a glance, calver on the other hand just says "newer version".

As others have mentioned, some combination of both approaches might give an extra data point for "freshness" especially if you're managing multiple versions, but even then what's wrong with just bumping the minor/patch?


I've done something similar to this in the past, only simpler: "YYYYMMDDXX" where XX is an incrementing index of today's releases.

It works well where you've got no commitment or requirement to release patches of old versions rather than roll forward. In my experience, that covers most internal software, where semver is overkill.


I've used the same format as you mentioned, usually for non-public-facing modules. Sometimes it starts with "YYYYMMDD", then "YYYYMMDD.XX" if needed.

Every version potentially breaks backward compatibility, regardless of versioning standard (semver, calver, or anything else). It's the responsibility of the module consumer to have tests and ensure its own functioning.

I do find semantic versioning useful for public-facing modules/interfaces, to indicate (or infer from the consumer side) the intended compatibility. In practice, though, sometimes patch versions break things, or major version upgrades work fine without any changes. So the consumer still needs to be responsible for ensuring compatibility - not much different than calendar versioning.


Yeah, that was my realisation. Semver ends up being a lie often enough, and back-ported patches happen rarely enough, that it ends up being engineering theatre more often than not.


You should probably look at updating your TLS. TLS 1.0 will be deprecated in 2 months.


TLS 1.0 won’t be deprecated in two months’ time, it’s being removed in two months’ time (from at least Firefox, Chrome and Safari; for IE and Edge Microsoft have just said the first half of the year). It’s already deprecated, has been for yonks.


You're quite right, and this site is being migrated this week. I was going to do it this morning, but there was a traffic spike for some reason? :)


All done, thanks again for looking out!


That's for web browsers though, which get to be early movers. In terms of the standards organisations the IETF's Best Common Practice update to deprecate TLS 1.0 (and TLS 1.1 which wasn't widely deployed before TLS 1.2 anyway) is still working its way through the bureaucracy. Currently:

https://tools.ietf.org/html/draft-ietf-tls-oldversions-depre...

Although I liked its original name (oldversions-die-die-die) obviously that's one of many things that couldn't survive in a publicly endorsed document.


For some projects I like the idea of calendar based versioning, sadly I mostly write Go and they've decided that anything but semver isn't allowed if you want to use the new packaging standard, Go Modules :(


Funny thing is, the previous tools for Go and tools in other languages tell you SemVer but you have enough control that you can use CalVer if you like.


At Cockroach Labs we switched to Calver covered in this thread https://news.ycombinator.com/item?id=19658969


I would have expected D to be short day (1, 2, 3 .. 29,30,31) and DD be zero padded (01,02,03 .. 29, 30, 31)

But other than that, I think it is a good idea to try and lay out a common language for the cases described.


Yeah, DD being short day is just wrong by conventional usage.



Recent discussion on chronological versioning: https://news.ycombinator.com/item?id=21929063


Whoah, that’s my project!


I could see this being useful in some cases for marketing disambiguation. The Wifi Alliance should be taking notes. Otherwise, I don't see any reason to use CalVer over SemVer.

I would rather the version numbers be used to inform users about the nature of the changes (patches, new features, backwards-incompatible interface changes) rather than simply when the change was published. I very rarely care about the publishing date.


I like that there's a standard page for this for reference, but I disagree with some of the use cases.

I think it makes sense in a few cases:

* Umbrella-type projects, such as an Operating System, with Ubuntu being a great example.

* Time-dependent projects (where it's more about data), such as tzdata, certificates, tax rates, etc.

* Constantly-changing APIs

I disagree with some of the projects listed, such as Unity and boltons (more on that below).

----

I think the trick to this working well is that at least one of the following must be true:

* You never break backwards compatibility. For example: tzdata, certificates

* There has to be another way to check dependencies. For example: the individual package versions used within Ubuntu

* Release notes (and upgrade notes) need to be really good. For example: include an "upgrade guide" that explicitly calls out breaking changes and how to fix them; summarize the major changes over time; make sure they're digestible by someone who is updating from a few major versions from a couple years ago (without having to read through each incremental guide).

----

Unity is actually a good counter-example to CalVer as it doesn't follow any of these rules. A quick search comes up with breaking changes in at least 2019.2.5, 2019.1.0 and 2018.3.0 [1]. To make things worse, they release frequently -- if I'm updating from say, 2018.2.0, there have been 85 (!) releases since then. The release notes are very detailed and on individual pages so it would be a multi-hour effort to read through to even figure out how complex it'll be to upgrade. This is especially annoying if I'm updating in a hurry to get an important security fix. At least with SemVer I could focus on the major releases.

[1] https://unity3d.com/unity/whats-new/2019.2.5, https://unity3d.com/unity/whats-new/2019.1.0, https://unity3d.com/unity/whats-new/unity-2018.3.0


APIs and libraries should tell us much more about their semantics so that we can assert compatibility directly rather than relying on a number


Wireguard uses a hybrid approach: 0.1.20191231

major.minor.YYYYMMDD


Nice. It puts the important stuff first, and even has a nice nested field at the end (which also puts the important stuff first).


I am just using major.YYYYMMDD.HHMMSS for some of my projects, e.g. https://pypi.org/project/better_exchook/ has the latest release 1.20191227.150050. I have never thought about version numbers for these projects anymore.


Any opinions on calver vs semver for, say, open source projects or APIs/SDKs?


For APIs, calver can make a lot of sense, as detailed in Stripe’s blog post on the subject https://stripe.com/en-ca/blog/api-versioning


That's just because they keep compatibility basically forever (they build middleware to transform older versions to new ones). If you actually want to remove old versions not so much.


This is great, thanks for sharing.


Semver is used for regular releases when you need to communicate deeper information to multiple consumers. A library version usually needs to communicate lots of information, to developers, to users, to distributions. Maybe this release is a dev release, while this other is stable, this release is LTS while another is not, this release has breaking changes, this one doesn't, etc.

Calver is used when you don't care about anything but the temporal difference between releases, and you can basically toss any expectation of compatibility between versions, other than something temporal ("this version is compatible with previous versions for up to one year"). That's why APIs use it.

Generally speaking, OSS uses Calver when the releaser doesn't need to care about the consumer, compatibility, etc. You'll find Linux system packages using Calver when someone basically cloned a random Git repo, made a one-off build, and decided "this will be a release" (you find this with firmware a lot), or as a way for 3rd parties to fork an official version with patches.

Random assortment of Ubuntu packages with a variant of Calver (sometimes along with Semver): libargon2, gyp, aspell, language-pack-en, libcrystalhd3, ntfs-3g, x11proto-* , python-cliapp, net-tools, rtmpdump, iputils-*, dh-python, amd64-microcode, lsb-release, libstring-escape-perl, wireless-regdb, ubuntu-keyring, tzdata, fonts-vlgothic, usb-modeswitch-data, publicsuffix, autotools-dev, geoip-database, ca-certificates, dns-root-data


tzdata and several other packages in that list use dated versions because they have very strong expectations of compatibility.


No strong opinion here, but I see calver as a good fit for a new / rapidly changing project (with yyyymmdd being a both version and snapshot date), or for a software where you don't need semver guarantees about api change - so not for a library or for some important tool that is often scripted.

Or, as described in the project, calver might be good as a release date for a "umbrella projects" - like Ubuntu, or even Windows 10 builds.


Semantic versioning tells you a lot about the state of a release. Is it supposed to break backwards compatibility or does it just add new or patch existing backwards compatible functionality? I think that sort of stuff is more important than on what day the release was made.

For an API it seems like a no-brainer to use semantic versioning, makes it easier to document feature deprecation, like supporting latest two major releases and so on.


Something like CalVer forces you to consider every version breaking and puts the responsibility on you to ensure compatibility with your project.

SemVer puts the responsibility on the maintainer to assume how users are using the library.

I think by now we've learned that even though SemVer was a good idea, people are people and they are gonna eventually fail at setting the version correctly, making your assumptions broken


Semver still communicates intents pretty well. Well run projects will even roll back changes that ended up being semver incompatible

Treating every patch release of Django like a major release would be a major waste of time compared to “assume Django maintainers have a good idea of how things are used, and rely on automated test suite”


> Semver still communicates intents pretty well. Well run projects will even roll back changes that ended up being semver incompatible

That sounds either worse. Software releases should be immutable, so no changing existing versions.

And also, if X.Y is incompatible (because they screwed up the versioning, as in your example), X.Z should also be incompatible (according to semver), otherwise you break semver twice instead of just once...

> Treating every patch release of Django like a major release would be a major waste of time

Yeah, I guess computing time. If you manually testing each dependency update, your doing something wrong. This should be automated to such level as you feel comfortable stuff is working by just running the tests.


Using a library puts the responsibility on you to ensure compatibility.

With SemVer the library maintainer tells you "here, let me help you". With CalVer the maintainer says "fuck that, I'm out". None changes your responsibility.


That can be said about any versioning scheme. The idea that making things inconvenient suddenly makes people do the right thing is pretty naive, if you ask me.

Semantic versioning lets the user decide.


At CoreOS (circa 2013+) we used something ideologically similar to CalVer but with tweaked semantics.

As per our documentation (https://coreos.com/releases/): CoreOS Container Linux version numbers are determined by the number of days since the CoreOS epoch, July 1, 2013, at the time the release is built for the Alpha channel.

There were definitely challenges but it provided a rigorous method to ensure monotonically increasing values. It had a useful side effect of getting people out of the habit of "caring" about which version they were running and instead allowed us to focus on simply "being up to date."


AWS seems to use a variation of calendar versioning for some of their APIs. In practice, it seems perfectly fine.


As does Azure


The unfortunate truth about calendar versioning is that it pushes devs and clients toward “freshness” instead of quality.

Same issue that we have in Apple’s design department: change for the sake of change.


People like bigger numbers and newer releases regardless of exact versioning scheme.

SemVer makes that situation worse, by requiring a bigger major release to break some part of the API. Other failure modes detailed here: https://sedimental.org/designing_a_version.html


Definitely a fair point. I think we’ve all seen at least one of our favourite pieces of software fall in to this when the company needed another major release to bring in funds.


Interesting to see that so many of the exemplary projects are python based. I wonder if there's any correlation there.


Just a bit of original author bias. If you know other projects, I'd be happy to merge em! https://github.com/mahmoud/calver


Amazon just adopted this for at least their FreeRTOS releases. 201912.00 is the latest. Handy enough to know how out of date you are - but overall fairly useless because I still need to go check and see what’s been released since. Not to mention some people might flinch if your latest release is 200501.00 even if it’s amazingly complete code.


You should probably consider changing the name. https://translate.google.com/?hl=fr#fr/en/calvaire


I mean, considering it's versioning, sounds about right, really.


Doesn't the prononciation differ -- ver vs. vaire?


No, same prononciation in French.


I thought the same!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: