53

How can I retrieve the Created date from the current .NET assembly?

I'd like to add some realy simple functionality where my app stops working one week after the build date of the main assembly. I already wrote the code that kills my app after a given date. I just need to programmatically retrieve the creation date from the assembly.

DenaliHardtail
  • 27,362
  • 56
  • 154
  • 233

7 Answers7

60

The following is based on: https://blog.codinghorror.com/determining-build-date-the-hard-way/

public static class ApplicationInformation
{
    /// <summary>
    /// Gets the executing assembly.
    /// </summary>
    /// <value>The executing assembly.</value>
    public static System.Reflection.Assembly ExecutingAssembly
    {
        get { return executingAssembly ?? (executingAssembly = System.Reflection.Assembly.GetExecutingAssembly()); }
    }
    private static System.Reflection.Assembly executingAssembly;

    /// <summary>
    /// Gets the executing assembly version.
    /// </summary>
    /// <value>The executing assembly version.</value>
    public static System.Version ExecutingAssemblyVersion
    {
        get { return executingAssemblyVersion ?? (executingAssemblyVersion = ExecutingAssembly.GetName().Version); }
    }
    private static System.Version executingAssemblyVersion;

    /// <summary>
    /// Gets the compile date of the currently executing assembly.
    /// </summary>
    /// <value>The compile date.</value>
    public static System.DateTime CompileDate
    {
        get
        {
            if (!compileDate.HasValue)
                compileDate = RetrieveLinkerTimestamp(ExecutingAssembly.Location);
            return compileDate ?? new System.DateTime();
        }
    }
    private static System.DateTime? compileDate;

    /// <summary>
    /// Retrieves the linker timestamp.
    /// </summary>
    /// <param name="filePath">The file path.</param>
    /// <returns></returns>
    /// <remarks>http://www.codinghorror.com/blog/2005/04/determining-build-date-the-hard-way.html</remarks>
    private static System.DateTime RetrieveLinkerTimestamp(string filePath)
    {
        const int peHeaderOffset = 60;
        const int linkerTimestampOffset = 8;
        var b = new byte[2048];
        System.IO.FileStream s = null;
        try
        {
            s = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            s.Read(b, 0, 2048);
        }
        finally
        {
            if(s != null)
                s.Close();
        }
        var dt = new System.DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(System.BitConverter.ToInt32(b, System.BitConverter.ToInt32(b, peHeaderOffset) + linkerTimestampOffset));
        return dt.AddHours(System.TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours);
    }
}
Bauer
  • 317
  • 3
  • 11
grenade
  • 31,451
  • 23
  • 97
  • 126
  • This makes a nice extension method on the Assembly class. – David Keaveny Feb 20 '13 at 22:11
  • 2
    Doesn't work for assemblies created via reflection (in memory). Those have no Location (empty string). – Thomas Weller Mar 10 '14 at 20:52
  • 24
    I wouldn't expect to find a compile date on an in-memory assembly just like I wouldn't expect to find zebra stripes on a pony. – grenade Mar 11 '14 at 05:17
  • 4
    I like this, my only change recently has been when it's compiled in one timezone but deployed in another (example: compiled on Build Server and deployed to Azure). In this case I've modified the last two lines like so: ' var dateUtcKind = DateTime.SpecifyKind(dt, DateTimeKind.Utc); return dateUtcKind;' – Rick Glos Jul 15 '14 at 22:33
  • Nice, just saved me a lot of headache :-) – chris Aug 25 '14 at 11:51
  • What for PCL (Phone, WinRT)? There's no ".Location" property on "Assembly" instances there. – Yves Schelpe Mar 20 '15 at 08:08
  • Similar answer [Displaying the build date](//stackoverflow.com/q/1600962) (from the same source) – Michael Freidgeim Feb 17 '17 at 06:56
  • This method is not reliable since sometimes (when linked with the undocumented `/Brepro`) `IMAGE_FILE_HEADER.TimeDateStamp` contains a hash instead of a timestamp. Quoting [Raymond Chen](https://blogs.msdn.microsoft.com/oldnewthing/20110713-00/?p=10173): _"The name timestamp is misleading. Its real purpose is to act as a signature so that the operating system can determine whether a DLL against which one set of values was precalculated matches the DLL physically on the system. A better name for it would have been UniqueId."_ For more bits of information see https://reviews.llvm.org/D51635 – Micha Wiedenmann Dec 10 '18 at 08:16
  • Notice that the linker timestamp suffers from the Y2038 problem, i.e., it will roll over in Jan 2038, just like all 32-bit Unix timestamps. – David R Tribble Sep 11 '20 at 15:57
  • Found this really interesting thanks for sharing, and for the date conversion I'm not sure if it works also with Azure compiled assemblies but I used the .ToLocalTime() method of the DateTime so: return dt.ToLocalTime(); Thanks for sharing this. – Sabrina_cs Jul 26 '22 at 08:57
49

I don't think the assembly itself contains it's creation date. I suspect the closest you can get is the creation date of the assembly file itself:

File.GetCreationTime(Assembly.GetExecutingAssembly().Location)

should do the trick.

EDIT:

I think Jeff Atwood's solution, written up by "grenade" in this thread, is probably the better way to go now.

Rob Levine
  • 40,328
  • 13
  • 85
  • 111
  • 8
    It works in most cases, but If one tries to use it in VSTO solution (for example Excel add-in), he'll always get Today's date because assembly files are being copied into AppData\Local\assembly folder before running the add-in inside Excel. – surfen Jul 27 '12 at 10:54
  • Also does not work if you copy it to a network of download it from ftp, etc – Lars Truijens May 29 '13 at 15:16
  • 1
    To be honest, I think Jeff Atwood's solution, written up by grenade in this thread, is probably the better way to go now. – Rob Levine May 30 '13 at 12:41
  • 4
    `GetLastWriteTime()` would be more accurate as to when it was built. `GetCreationTime()` would simply return the first build created after cleaning the project – Jay Wick Feb 02 '14 at 14:33
  • Doesn't work for assemblies created via reflection (in memory). – Thomas Weller Mar 10 '14 at 20:50
35

What's wrong with:

System.IO.File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location);
Wim
  • 11,998
  • 1
  • 34
  • 57
  • This is much better because I have multiple DLL's being updated. Thanks! – Andrew Quaschnick Jan 30 '14 at 23:39
  • 3
    Much better. `GetCreationTime()` returns the time when the assembly was FIRST created. This does not return the time when the assembly was LAST created. – Jop Apr 25 '14 at 07:59
9

Maybe this post on coding horror may help

jmlumpkin
  • 922
  • 2
  • 14
  • 34
  • updated link, although several other answers here do the same thing or reference this articles new location – jmlumpkin May 16 '14 at 15:52
6

This should work:

var entryAssembly = Assembly.GetEntryAssembly();
var fileInfo = new FileInfo(entryAssembly.Location);
var buildDate = fileInfo.LastWriteTime;
Jake Pearson
  • 27,069
  • 12
  • 75
  • 95
2

The best way to do this would be with a custom attribute that you set on the PreBuild of your assembly.

And then use the standard reflection to get the attribute you created.

But out of curiosity, why kill the app after the BUILD date?

Paulo Santos
  • 11,285
  • 4
  • 39
  • 65
  • Doesn't need to be the build date. I just picked that date because I knew that date would change automatically as the app is built. The goal, I only want to allow the app to function for about a week. I could also hardcode a date into the code but would need to change that variable as changes are made to the app. – DenaliHardtail Jan 12 '10 at 16:28
  • @Scott but than your way to kill the app, is easily circumvented. – Paulo Santos Jan 12 '10 at 17:35
  • 1
    Killing the app based on build date seems like a good way of reducing noise when doing alpha testing in a unstructured environment (i.e. internet volunteers). This way you avoid people downloading the lastest alpha, forgetting it for 3 weeks, and then testing and reporting a lot of bugs that have already been dealt with. It ensures that alpha testers are always using a recent version of the app, without having something that could introduce even more bugs at that stage like an auto-update feature. – David Jan 12 '10 at 19:22
  • 1
    @Paul - you are correct. It is easily circumvented but this is not about security or copy protection. I need a quick and dirty way to put an expiration date on builds. – DenaliHardtail Jan 13 '10 at 18:40
  • That's a good answer. Because file modification time is absolutely not reliable. – nightcoder Mar 06 '13 at 01:43
1

If you're writing an application for a mobile device using the compact framwork, Assembly.Location is not available.

Here, I found an alternative:

     System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)
realbart
  • 3,497
  • 1
  • 25
  • 37