Mostrar la fecha de compilación


Actualmente tengo una aplicación que muestra el número de compilación en su ventana de título. Eso está muy bien, excepto que no significa nada para la mayoría de los usuarios, que quieren saber si tienen la última compilación - tienden a referirse a ella como "del jueves pasado" en lugar de construir 1.0.8.4321.

El plan es poner la fecha de compilación allí en su lugar, por ejemplo, "App built on 21/10/2009".

Estoy luchando para encontrar una forma programática de extraer la fecha de compilación como una cadena de texto para usar como este.

Para el número de compilación, utilicé:

Assembly.GetExecutingAssembly().GetName().Version.ToString()

Después de definir cómo surgieron.

Me gustaría algo así para la fecha de compilación (y la hora, para los puntos de bonificación).

Los punteros aquí son muy apreciados (excuse pun si es apropiado), o soluciones más ordenadas...

Author: Luke Girvin, 2009-10-21

22 answers

Jeff Atwood tenía algunas cosas que decir sobre este tema en Determinar la Fecha de construcción de la manera difícil .

El método más confiable resulta ser recuperar la marca de tiempo del enlazador desde el encabezado PE incrustado en el archivo ejecutable some algo de código C# (por Joe Spivey) para eso de los comentarios al artículo de Jeff:

public static DateTime GetLinkerTime(this Assembly assembly, TimeZoneInfo target = null)
{
    var filePath = assembly.Location;
    const int c_PeHeaderOffset = 60;
    const int c_LinkerTimestampOffset = 8;

    var buffer = new byte[2048];

    using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        stream.Read(buffer, 0, 2048);

    var offset = BitConverter.ToInt32(buffer, c_PeHeaderOffset);
    var secondsSince1970 = BitConverter.ToInt32(buffer, offset + c_LinkerTimestampOffset);
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    var linkTimeUtc = epoch.AddSeconds(secondsSince1970);

    var tz = target ?? TimeZoneInfo.Local;
    var localTime = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tz);

    return localTime;
}

Ejemplo de uso:

var linkTimeLocal = Assembly.GetExecutingAssembly().GetLinkerTime();

ACTUALIZACIÓN: El método estaba funcionando para. Net Core 1.0, pero dejó de funcionar después de. Net Core 1.1 liberación (da años aleatorios en el rango 1900-2020)

 338
Author: mdb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-29 07:16:54

El nuevo camino

Cambié de opinión sobre esto, y actualmente uso este truco para obtener la fecha de compilación correcta.

#region Gets the build date and time (by reading the COFF header)

// http://msdn.microsoft.com/en-us/library/ms680313

struct _IMAGE_FILE_HEADER
{
    public ushort Machine;
    public ushort NumberOfSections;
    public uint TimeDateStamp;
    public uint PointerToSymbolTable;
    public uint NumberOfSymbols;
    public ushort SizeOfOptionalHeader;
    public ushort Characteristics;
};

static DateTime GetBuildDateTime(Assembly assembly)
{
    var path = assembly.GetName().CodeBase;
    if (File.Exists(path))
    {
        var buffer = new byte[Math.Max(Marshal.SizeOf(typeof(_IMAGE_FILE_HEADER)), 4)];
        using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            fileStream.Position = 0x3C;
            fileStream.Read(buffer, 0, 4);
            fileStream.Position = BitConverter.ToUInt32(buffer, 0); // COFF header offset
            fileStream.Read(buffer, 0, 4); // "PE\0\0"
            fileStream.Read(buffer, 0, buffer.Length);
        }
        var pinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try
        {
            var coffHeader = (_IMAGE_FILE_HEADER)Marshal.PtrToStructure(pinnedBuffer.AddrOfPinnedObject(), typeof(_IMAGE_FILE_HEADER));

            return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1) + new TimeSpan(coffHeader.TimeDateStamp * TimeSpan.TicksPerSecond));
        }
        finally
        {
            pinnedBuffer.Free();
        }
    }
    return new DateTime();
}

#endregion

La vieja manera

Bueno, ¿cómo se generan los números de compilación? Visual Studio (o el compilador de C#) en realidad proporciona números de compilación y revisión automáticos si cambia el atributo AssemblyVersion a, por ejemplo, 1.0.*

Lo que sucederá es que la compilación será igual al número de días desde el 1 de enero de 2000, hora local, y que la revisión sea igual al número de segundos desde la hora local de medianoche, dividido por 2.

Ver Contenido de la Comunidad, Números automáticos de Compilación y Revisión

Por ejemplo, AssemblyInfo. cs

[assembly: AssemblyVersion("1.0.*")] // important: use wildcard for build and revision numbers!

Código de muestra.cs

var version = Assembly.GetEntryAssembly().GetName().Version;
var buildDateTime = new DateTime(2000, 1, 1).Add(new TimeSpan(
TimeSpan.TicksPerDay * version.Build + // days since 1 January 2000
TimeSpan.TicksPerSecond * 2 * version.Revision)); // seconds since midnight, (multiply by 2 to get original)
 82
Author: John Leidegren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-29 12:35:47

Añadir a continuación a la línea de comandos del evento pre-build:

echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"

Añadir este archivo como recurso, ahora tienes la cadena 'BuildDate' en tus recursos.

Para crear recursos, consulte Cómo crear y utilizar recursos en. NET .

 79
Author: Abdurrahim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:17

Añadir a continuación a la línea de comandos del evento pre-build:

echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"

Agregue este archivo como recurso, ahora tiene la cadena 'BuildDate' en sus recursos.

Después de insertar el archivo en el Recurso (como archivo de texto público), accedí a él a través de

string strCompTime = Properties.Resources.BuildDate;

Para crear recursos, consulte Cómo crear y utilizar recursos en. NET .

 35
Author: brewmanz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:43

Un enfoque que me sorprende que nadie haya mencionado todavía es usar Plantillas de texto T4 para la generación de código.

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ output extension=".g.cs" #>
namespace Foo.Bar
{
    public static partial class Constants
    {
        public static DateTime CompilationTimestampUtc { get { return new DateTime(<# Write(DateTime.UtcNow.Ticks); #>L, DateTimeKind.Utc); } }
    }
}

Ventajas:

  • Independiente de la localización
  • Permite mucho más que solo el momento de compilación

Contras:

 13
Author: Peter Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:43

Solo soy un novato de C#, así que tal vez mi respuesta suene tonta: Muestro la fecha de compilación desde la fecha en que se escribió por última vez el archivo ejecutable:

string w_file = "MyProgram.exe"; 
string w_directory = Directory.GetCurrentDirectory();

DateTime c3 =  File.GetLastWriteTime(System.IO.Path.Combine(w_directory, w_file));
RTB_info.AppendText("Program created at: " + c3.ToString());

Intenté usar File.Método GetCreationTime pero obtuvo resultados extraños: la fecha del comando fue 2012-05-29, pero la fecha del Explorador de ventanas mostró 2012-05-23. Después de buscar esta discrepancia, encontré que el archivo probablemente se creó el 2012-05-23 (como se muestra en el Explorador de Windows), pero se copió a la carpeta actual el 2012-05-29 (como se muestra en File.GetCreationTime comando) - así que para estar en el lado seguro estoy usando Archivo.Comando GetLastWriteTime.

Zalek

 12
Author: Zalek Bloom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-15 15:00:02

La opción no discutida aquí es insertar sus propios datos en AssemblyInfo.cs, el campo" AssemblyInformationalVersion " parece apropiado: tenemos un par de proyectos en los que estábamos haciendo algo similar como paso de compilación (sin embargo, no estoy completamente satisfecho con la forma en que funciona, así que realmente no quiero reproducir lo que tenemos).

Hay un artículo sobre el tema en codeproject: http://www.codeproject.com/KB/dotnet/Customizing_csproj_files.aspx

 8
Author: Murph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 14:08:43

Para cualquiera que necesite obtener el tiempo de compilación en Windows 8 / Windows Phone 8:

    public static async Task<DateTimeOffset?> RetrieveLinkerTimestamp(Assembly assembly)
    {
        var pkg = Windows.ApplicationModel.Package.Current;
        if (null == pkg)
        {
            return null;
        }

        var assemblyFile = await pkg.InstalledLocation.GetFileAsync(assembly.ManifestModule.Name);
        if (null == assemblyFile)
        {
            return null;
        }

        using (var stream = await assemblyFile.OpenSequentialReadAsync())
        {
            using (var reader = new DataReader(stream))
            {
                const int PeHeaderOffset = 60;
                const int LinkerTimestampOffset = 8;

                //read first 2048 bytes from the assembly file.
                byte[] b = new byte[2048];
                await reader.LoadAsync((uint)b.Length);
                reader.ReadBytes(b);
                reader.DetachStream();

                //get the pe header offset
                int i = System.BitConverter.ToInt32(b, PeHeaderOffset);

                //read the linker timestamp from the PE header
                int secondsSince1970 = System.BitConverter.ToInt32(b, i + LinkerTimestampOffset);

                var dt = new DateTimeOffset(1970, 1, 1, 0, 0, 0, DateTimeOffset.Now.Offset) + DateTimeOffset.Now.Offset;
                return dt.AddSeconds(secondsSince1970);
            }
        }
    }

Para cualquiera que necesite obtener el tiempo de compilación en Windows Phone 7:

    public static async Task<DateTimeOffset?> RetrieveLinkerTimestampAsync(Assembly assembly)
    {
        const int PeHeaderOffset = 60;
        const int LinkerTimestampOffset = 8;            
        byte[] b = new byte[2048];

        try
        {
            var rs = Application.GetResourceStream(new Uri(assembly.ManifestModule.Name, UriKind.Relative));
            using (var s = rs.Stream)
            {
                var asyncResult = s.BeginRead(b, 0, b.Length, null, null);
                int bytesRead = await Task.Factory.FromAsync<int>(asyncResult, s.EndRead);
            }
        }
        catch (System.IO.IOException)
        {
            return null;
        }

        int i = System.BitConverter.ToInt32(b, PeHeaderOffset);
        int secondsSince1970 = System.BitConverter.ToInt32(b, i + LinkerTimestampOffset);
        var dt = new DateTimeOffset(1970, 1, 1, 0, 0, 0, DateTimeOffset.Now.Offset) + DateTimeOffset.Now.Offset;
        dt = dt.AddSeconds(secondsSince1970);
        return dt;
    }

NOTA: En todos los casos se está ejecutando en un sandbox, por lo que solo podrá obtener el tiempo de compilación de los ensamblados que implementa con su aplicación. (es decir, esto no funcionará en nada en el GAC).

 8
Author: Matt Dotson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-21 02:54:38

El método anterior se puede ajustar para ensamblajes ya cargados dentro del proceso mediante el uso de la imagen del archivo en memoria (en lugar de volver a leerlo desde el almacenamiento):

using System;
using System.Runtime.InteropServices;
using Assembly = System.Reflection.Assembly;

static class Utils
{
    public static DateTime GetLinkerDateTime(this Assembly assembly, TimeZoneInfo tzi = null)
    {
        // Constants related to the Windows PE file format.
        const int PE_HEADER_OFFSET = 60;
        const int LINKER_TIMESTAMP_OFFSET = 8;

        // Discover the base memory address where our assembly is loaded
        var entryModule = assembly.ManifestModule;
        var hMod = Marshal.GetHINSTANCE(entryModule);
        if (hMod == IntPtr.Zero - 1) throw new Exception("Failed to get HINSTANCE.");

        // Read the linker timestamp
        var offset = Marshal.ReadInt32(hMod, PE_HEADER_OFFSET);
        var secondsSince1970 = Marshal.ReadInt32(hMod, offset + LINKER_TIMESTAMP_OFFSET);

        // Convert the timestamp to a DateTime
        var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        var linkTimeUtc = epoch.AddSeconds(secondsSince1970);
        var dt = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tzi ?? TimeZoneInfo.Local);
        return dt;
    }
}
 8
Author: tcostin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-15 20:09:50

Con respecto a la técnica de extraer la fecha de compilación/información de la versión de los bytes de un encabezado de ensamblado PE, Microsoft ha cambiado los parámetros de compilación predeterminados a partir de Visual Studio 15.4. El nuevo valor predeterminado incluye la compilación determinista, que hace que una marca de tiempo válida y los números de versión incrementados automáticamente sean cosa del pasado. El campo de marca de tiempo todavía está presente, pero se llena con un valor permanente que es un hash de algo u otro, pero no cualquier indicación de la compilación tiempo.

Http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html Algunos antecedentes detallados aquí

Para aquellos que priorizan una marca de tiempo útil sobre la compilación determinista, hay una manera de anular el nuevo valor predeterminado. Puede incluir una etiqueta en el .csproj archivo de la asamblea de interés de la siguiente manera:

  <PropertyGroup>
      ...
      <Deterministic>false</Deterministic>
  </PropertyGroup>

Actualizar: Apoyo la solución de plantilla de texto T4 descrita en otra respuesta aquí. Lo usé para resolver mi problema limpiamente sin perder el beneficio de la compilación determinista. Una advertencia al respecto es que Visual Studio solo ejecuta el compilador T4 cuando se guarda el archivo .tt, no en el momento de la compilación. Esto puede ser incómodo si se excluye el.cs resultado del control de código fuente (ya que se espera que se genere) y otro desarrollador comprueba el código. Sin volver a guardar, no tendrán el .archivo CS. Hay un paquete en nuget (creo que llamado AutoT4) que hace que la compilación T4 sea parte de cada compilación. Todavía no he enfrenté la solución a esto durante el despliegue de producción, pero espero que algo similar lo haga bien.

 8
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-14 17:49:39

Muchas respuestas excelentes aquí, pero siento que puedo agregar las mías debido a la simplicidad, el rendimiento (en comparación con las soluciones relacionadas con los recursos) multiplataforma (funciona con Net Core también) y evitar cualquier herramienta de terceros. Simplemente agregue este objetivo de msbuild al csproj.

<Target Name="Date" BeforeTargets="CoreCompile">
    <WriteLinesToFile File="$(IntermediateOutputPath)gen.cs" Lines="static partial class Builtin { public static long CompileTime = $([System.DateTime]::UtcNow.Ticks) %3B }" Overwrite="true" />
    <ItemGroup>
        <Compile Include="$(IntermediateOutputPath)gen.cs" />
    </ItemGroup>
</Target>

Y ahora tienes Builtin.CompileTime o new DateTime(Builtin.CompileTime, DateTimeKind.Utc) si lo necesitas de esa manera.

A ReSharper no le va a gustar. Puede ignorarlo o agregar una clase parcial al proyecto también, pero funciona de todos modos.
 3
Author: Dmitry Gusarov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-18 08:06:16

Puede usar un evento post-build del proyecto para escribir un archivo de texto en su directorio de destino con la fecha y hora actual. A continuación, puede leer el valor en tiempo de ejecución. Es un poco complicado, pero debería funcionar.

 2
Author: MikeWyatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 13:58:47

No estoy seguro, pero tal vez el Incrementador de compilación ayuda.

 2
Author: Bobby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-28 02:36:19

Un enfoque diferente, compatible con PCL sería usar una tarea en línea de MSBuild para sustituir el tiempo de compilación en una cadena que es devuelta por una propiedad en la aplicación. Estamos utilizando este enfoque con éxito en una aplicación que tiene Xamarin.Formularios, Xamarin.Androide, y Xamarin.Proyectos iOS.

EDITAR:

Simplificado moviendo toda la lógica en el archivo SetBuildDate.targets, y usando Regex en lugar de reemplazar cadena simple para que el archivo pueda ser modificado por cada compilación sin un "restablecer".

La definición de tarea en línea de MSBuild (guardada en SetBuildDate.archivo de destino local al Xamarin.Proyecto de formularios para este ejemplo):

<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="12.0">

  <UsingTask TaskName="SetBuildDate" TaskFactory="CodeTaskFactory" 
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
    <ParameterGroup>
      <FilePath ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs"><![CDATA[

        DateTime now = DateTime.UtcNow;
        string buildDate = now.ToString("F");
        string replacement = string.Format("BuildDate => \"{0}\"", buildDate);
        string pattern = @"BuildDate => ""([^""]*)""";
        string content = File.ReadAllText(FilePath);
        System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex(pattern);
        content = rgx.Replace(content, replacement);
        File.WriteAllText(FilePath, content);
        File.SetLastWriteTimeUtc(FilePath, now);

   ]]></Code>
    </Task>
  </UsingTask>

</Project>

Invocando la tarea inline anterior en el Xamarin.Forms csproj file in target BeforeBuild:

  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.  -->
  <Import Project="SetBuildDate.targets" />
  <Target Name="BeforeBuild">
    <SetBuildDate FilePath="$(MSBuildProjectDirectory)\BuildMetadata.cs" />
  </Target>

La propiedad FilePath se establece en un archivo BuildMetadata.cs en el Xamarin.Forma un proyecto que contiene una clase simple con una propiedad string BuildDate, en la que se sustituirá el tiempo de compilación:

public class BuildMetadata
{
    public static string BuildDate => "This can be any arbitrary string";
}

Agregue este archivo BuildMetadata.cs a proyecto. Será modificado por cada compilación, pero de una manera que permita compilaciones repetidas (reemplazos repetidos), por lo que puede incluirlo u omitirlo en el control de código fuente según lo desee.

 2
Author: Mark Larter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-10 14:10:22

En 2018 algunas de las soluciones anteriores ya no funcionan o no funcionan con.NET Core.

Utilizo el siguiente enfoque que es simple y funciona para mi proyecto.NET Core 2.0.

Añadir lo siguiente a su .csproj dentro del grupo de propiedades:

    <Today>$([System.DateTime]::Now)</Today>

Esto define una PropertyFunction a la que puede acceder en su comando pre build.

Su pre-construcción se ve así

echo $(today) > $(ProjectDir)BuildTimeStamp.txt

Establece la propiedad del BuildTimeStamp.txt a Incrustado recurso.

Ahora puedes leer la marca de tiempo así

public static class BuildTimeStamp
    {
        public static string GetTimestamp()
        {
            var assembly = Assembly.GetEntryAssembly(); 

            var stream = assembly.GetManifestResourceStream("NamespaceGoesHere.BuildTimeStamp.txt");

            using (var reader = new StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }
    }
 2
Author: Postlagerkarte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-12 15:04:52

Necesitaba una solución universal que funcionara con un proyecto NETStandard en cualquier plataforma (iOS, Android y Windows.) Para lograr esto, decidí generar automáticamente un archivo CS a través de un script de PowerShell. Aquí está el script de PowerShell:

param($outputFile="BuildDate.cs")

$buildDate = Get-Date -date (Get-Date).ToUniversalTime() -Format o
$class = 
"using System;
using System.Globalization;

namespace MyNamespace
{
    public static class BuildDate
    {
        public const string BuildDateString = `"$buildDate`";
        public static readonly DateTime BuildDateUtc = DateTime.Parse(BuildDateString, null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
    }
}"

Set-Content -Path $outputFile -Value $class

Guarde el archivo PowerScript como GenBuildDate.ps1 y añádalo a su proyecto. Finalmente, agrega la siguiente línea a tu evento Pre-Build:

powershell -File $(ProjectDir)GenBuildDate.ps1 -outputFile $(ProjectDir)BuildDate.cs

Asegúrese de BuildDate.cs está incluido en su proyecto. Funciona como un campeón en cualquier sistema operativo!

 2
Author: David Tosi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-21 16:21:52

Una pequeña actualización sobre la respuesta "New Way" de Jhon.

Necesita construir la ruta en lugar de usar la cadena de base de código cuando se trabaja con ASP.NET/MVC

    var codeBase = assembly.GetName().CodeBase;
    UriBuilder uri = new UriBuilder(codeBase);
    string path = Uri.UnescapeDataString(uri.Path);
 2
Author: Thadeu Antonio Ferreira Melo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-04 13:21:58

Para los proyectos.NET Core, adapté la respuesta de Postlagerkarte para actualizar el campo de Derechos de autor del ensamblado con la fecha de compilación.

Editar directamente csproj

Lo siguiente se puede agregar directamente al primer PropertyGroup en el csproj:

<Copyright>Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))</Copyright>

Alternativa: Propiedades del proyecto de Visual Studio

O pegue la expresión interna directamente en el campo Copyright de la sección Package de las propiedades del proyecto en Visual Studio:

Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))

Esto puede ser un poco confuso, porque Visual Studio evaluará la expresión y mostrará el valor actual en la ventana, pero también actualizará el archivo de proyecto adecuadamente detrás de escena.

Toda la solución vía Directorio.Construir.props

Puede colocar el elemento <Copyright> anterior en un archivo Directory.Build.props en la raíz de su solución y aplicarlo automáticamente a todos los proyectos dentro del directorio, suponiendo que cada proyecto no proporcione su propio valor de copyright.

<Project>
 <PropertyGroup>
   <Copyright>Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))</Copyright>
 </PropertyGroup>
</Project>

Directorio.Construir.apoyos: Personaliza tu compilación

Salida

La expresión de ejemplo le dará un copyright como este:

Copyright © 2018 Travis Troyer (2018-05-30T14:46:23)

Recuperación

Puede ver la información de derechos de autor de las propiedades del archivo en Windows, o grabarla en tiempo de ejecución:

var version = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location);

Console.WriteLine(version.LegalCopyright);
 2
Author: Travis Troyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-30 15:03:00

Podría iniciar un paso adicional en el proceso de compilación que escribe una marca de fecha en un archivo que luego se puede mostrar.

En la pestaña propiedades del proyecto, busque en la pestaña eventos de compilación. Hay una opción para ejecutar un comando pre o post build.

 1
Author: Guy van den Berg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-21 13:58:39

Usé la sugerencia de Abdurrahim. Sin embargo, parecía dar un formato de hora extraño y también agregó la abreviatura para el día como parte de la fecha de compilación; ejemplo: Sun 12/24/2017 13:21:05.43. Solo necesitaba la fecha, así que tuve que eliminar el resto usando subcadena.

Después de agregar el echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt" al evento pre-build, simplemente hice lo siguiente:

string strBuildDate = YourNamespace.Properties.Resources.BuildDate;
string strTrimBuildDate = strBuildDate.Substring(4).Remove(10);

La buena noticia aquí es que funcionó.

 1
Author: DemarcPoint,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-24 20:57:53

Si esta es una aplicación de Windows, solo puede usar la ruta ejecutable de la aplicación: nuevo System.IO.FileInfo(Application.ExecutablePath). LastWriteTime.toString("aaaa.MM. dd")

 0
Author: John Clark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-19 14:25:05

Puedes usar este proyecto: https://github.com/dwcullop/BuildInfo

Aprovecha T4 para automatizar la fecha de compilación. Hay varias versiones (diferentes ramas), incluida una que te da el Hash de Git de la rama actualmente descargada, si te gustan ese tipo de cosas.

Divulgación: Yo escribí el módulo.

 0
Author: Darrin Cullop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-22 20:29:27