Question

Je dispose actuellement d'une application affichant le numéro de build dans sa fenêtre de titre. C'est bien beau, sauf que cela ne signifie rien pour la plupart des utilisateurs, qui veulent savoir s'ils disposent de la dernière version - ils ont tendance à s'y référer comme & "; Jeudi &"; plutôt que de construire 1.0.8.4321.

Le plan est de mettre la date de construction à la place - Donc, & "App créée le 21/10/2009 &"; par exemple.

J'ai du mal à trouver un moyen par programme d'extraire la date de construction sous forme de chaîne de texte à utiliser de la sorte.

Pour le numéro de build, j'ai utilisé:

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

après avoir défini comment ceux-ci sont apparus.

Je voudrais quelque chose comme ça pour la date de compilation (et l'heure, pour les points bonus).

Les pointeurs ici sont très appréciés (excusez le jeu de mots si approprié), ou des solutions plus ordonnées ...

Était-ce utile?

La solution

Jeff Atwood avait quelques choses à dire sur ce problème dans Déterminer Date de construction à la dure .

La méthode la plus fiable consiste à récupérer l'horodatage de l'éditeur de liens à partir de En-tête PE incorporé dans le fichier exécutable - du code C # (par Joe Spivey) pour cela, dans les commentaires de l'article 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;
}

Exemple d'utilisation:

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

UPDATE: la méthode fonctionnait pour .Net Core 1.0, mais cessait de fonctionner après la publication de .Net Core 1.1 (donne des années aléatoires dans la plage 1900-2020)

Autres conseils

Ajouter ci-dessous à la ligne de commande de l'événement de pré-génération:

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

Ajouter ce fichier en tant que ressource, vous avez maintenant la chaîne 'BuildDate' dans vos ressources.

Pour créer des ressources, voir Comment créer et utiliser des ressources dans. NET .

La voie

Comme l'a souligné @ c00000fd dans les commentaires . . Microsoft est en train de changer cela. Et bien que beaucoup de gens n'utilisent pas la dernière version de leur compilateur, je soupçonne que ce changement rend cette approche indiscutablement mauvaise. Et même s’il s’agit d’un exercice amusant, je recommanderais aux gens d’intégrer simplement une date de construction à leur binaire par tout autre moyen nécessaire s’il est important de suivre la date de construction du binaire lui-même.

Cela peut être fait avec une génération de code triviale qui est probablement déjà la première étape de votre script de construction. Cela, et le fait que les outils ALM / Build / DevOps aident beaucoup à cela et devraient être préférés à toute autre chose.

Je laisse ici le reste de cette réponse à des fins historiques uniquement.

La nouvelle façon

J'ai changé d'avis à ce sujet et utilise actuellement cette astuce pour obtenir la date de construction correcte.

#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

À l'ancienne

Eh bien, comment générez-vous des numéros de build? Visual Studio (ou le compilateur C #) fournit en fait des numéros de construction et de révision automatiques si vous changez l'attribut AssemblyVersion en, par exemple. 1.0.*

Ce qui va arriver, c’est que le build sera égal au nombre de jours depuis le 1er janvier 2000 heure locale et que la révision sera égale au nombre de secondes écoulées depuis minuit heure locale, divisé par 2.

voir Contenu de la communauté, Numéros de construction et de révision automatiques

par exemple. AssemblyInfo.cs

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

SampleCode.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)

Ajouter ci-dessous à la ligne de commande de l'événement de pré-génération:

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

Ajoutez ce fichier en tant que ressource. Vous disposez maintenant de la chaîne 'BuildDate' dans vos ressources.

Après avoir inséré le fichier dans la ressource (sous forme de fichier texte public), je l'ai accédé via

string strCompTime = Properties.Resources.BuildDate;

Pour créer des ressources, voir Comment créer et utiliser des ressources dans. NET .

Je suis étonné que personne n'ait encore mentionné cette approche consiste à utiliser Modèles de texte T4 pour la génération de code.

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

Avantages:

  • Indépendant de la localisation
  • Permet beaucoup plus que le temps de compilation

Inconvénients:

En ce qui concerne la technique d'extraction des informations de date / version de construction à partir des octets d'un en-tête PE d'assemblage, Microsoft a modifié les paramètres de génération par défaut à partir de Visual Studio 15.4. La nouvelle valeur par défaut inclut la compilation déterministe, qui rend le timestamp valide et les numéros de version incrémentés automatiquement obsolètes. Le champ d'horodatage est toujours présent mais il est rempli avec une valeur permanente qui est un hachage de quelque chose, mais pas d'indication du temps de construction.

Quelques informations détaillées ici

Pour ceux qui privilégient un horodatage utile par rapport à la compilation déterministe, il existe un moyen de remplacer le nouveau paramètre par défaut. Vous pouvez inclure une balise dans le fichier .csproj de l’assemblée d’intérêt, comme suit:

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

Mise à jour: J'approuve la solution de modèle de texte T4 décrite dans une autre réponse ici. Je l'ai utilisé pour résoudre mon problème proprement sans perdre l'avantage de la compilation déterministe. Une précaution à ce sujet est que Visual Studio n'exécute le compilateur T4 que lorsque le fichier .tt est enregistré, pas au moment de la génération. Cela peut être gênant si vous excluez le résultat .cs du contrôle de code source (car vous vous attendez à ce qu'il soit généré) et qu'un autre développeur extrait le code. Sans réenregistrer, ils n'auront pas le fichier .cs. Il existe un paquet sur nuget (appelé AutoT4 à mon avis) qui fait de la compilation T4 une partie de chaque construction. Je n'ai pas encore confronté la solution à ce problème lors du déploiement en production, mais je m'attends à ce que quelque chose de similaire réussisse.

Je ne suis qu'un débutant en C #, alors peut-être que ma réponse semble stupide. J'affiche la date de compilation à partir de la date à laquelle le fichier exécutable a été écrit pour la dernière fois:

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());

J'ai essayé d'utiliser la méthode File.GetCreationTime mais j'ai obtenu des résultats étranges: la date de la commande était le 2012-05-29, mais la date de l'Explorateur Windows indiquait le 2012-05-23. Après avoir recherché cette anomalie, j'ai constaté que le fichier avait probablement été créé le 2012-05-23 (comme le montre l'explorateur Windows), mais copié dans le dossier actuel le 2012-05-29 (comme le montre la commande File.GetCreationTime) - donc pour être sûr, j'utilise la commande File.GetLastWriteTime.

Zalek

Pour tous ceux qui ont besoin de connaître le temps de compilation sous 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);
            }
        }
    }

Pour tous ceux qui ont besoin de connaître le temps de compilation dans 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;
    }

REMARQUE: dans tous les cas, vous utilisez une sandbox, vous ne pourrez donc obtenir que le temps de compilation des assemblys que vous déployez avec votre application. (c’est-à-dire que cela ne fonctionnera dans rien dans le GAC).

La méthode ci-dessus peut être modifiée pour les assemblages déjà chargés dans le processus en utilisant l'image du fichier en mémoire (au lieu de la relire à partir de la mémoire):

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;
    }
}

L'option non décrite ici consiste à insérer vos propres données dans AssemblyInfo.cs, le " AssemblyInformationalVersion " le terrain semble approprié - nous avons quelques projets dans lesquels nous faisions quelque chose de similaire en tant qu'étape de construction (cependant, je ne suis pas entièrement satisfait de la façon dont cela fonctionne, vous ne voulez donc pas vraiment reproduire ce que nous avons).

Il y a un article à ce sujet sur codeproject: http://www.codeproject.com /KB/dotnet/Customizing_csproj_files.aspx

Pour les projets .NET Core, j'ai adapté la réponse de Postlagerkarte afin de mettre à jour le champ Copyright de l'assembly avec la date de construction.

Modifiez directement csproj

Les éléments suivants peuvent être ajoutés directement au premier PropertyGroup dans le fichier csproj:

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

Alternative: propriétés du projet Visual Studio

Ou collez l'expression interne directement dans le champ Copyright de la section Package des propriétés du projet dans Visual Studio:

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

Cela peut être un peu déroutant, car Visual Studio évaluera l'expression et affichera la valeur actuelle dans la fenêtre, mais mettra également à jour le fichier de projet en arrière-plan.

À l'échelle de la solution via Directory.Build.props

Vous pouvez insérer l'élément <Copyright> ci-dessus dans un fichier Directory.Build.props situé dans la racine de votre solution et l'appliquer automatiquement à tous les projets du répertoire, en supposant que chaque projet ne fournisse pas sa propre valeur Copyright.

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

Directory.Build.props: Personnalisez votre version

Sortie

L'exemple d'expression vous donnera un copyright comme celui-ci:

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

Récupération

Vous pouvez afficher les informations de copyright des propriétés du fichier dans Windows ou les récupérer au moment de l'exécution:

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

Console.WriteLine(version.LegalCopyright);

Beaucoup de bonnes réponses ici, mais j’ai l’impression que je peux ajouter les miennes pour des raisons de simplicité, de performances (comparées aux solutions liées aux ressources), multiplates-formes (fonctionne également avec Net Core) et pour éviter tout outil tiers. Ajoutez simplement cette cible msbuild au 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>

et maintenant vous avez Builtin.CompileTime ou new DateTime(Builtin.CompileTime, DateTimeKind.Utc) si vous en avez besoin de cette façon.

ReSharper ne va pas l’aimer. Vous pouvez l’ignorer ou ajouter une classe partielle au projet, mais cela fonctionne quand même.

En 2018, certaines des solutions ci-dessus ne fonctionnent plus ou ne fonctionnent pas avec .NET Core.

J'utilise l'approche suivante qui est simple et qui fonctionne pour mon projet .NET Core 2.0.

Ajoutez les éléments suivants à votre fichier .csproj dans le PropertyGroup:

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

Ceci définit un PropertyFunction auquel vous pouvez accéder dans votre commande de pré-génération.

Votre pré-génération ressemble à ceci

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

Définissez la propriété du fichier BuildTimeStamp.txt sur une ressource incorporée.

Vous pouvez maintenant lire l'horodatage comme ceci

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();
            }
        }
    }

J'avais besoin d'une solution universelle fonctionnant avec un projet NETStandard sur n'importe quelle plate-forme (iOS, Android et Windows). Pour ce faire, j'ai décidé de générer automatiquement un fichier CS via un script PowerShell. Voici le script 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

Enregistrez le fichier PowerScript sous GenBuildDate.ps1 et ajoutez-le à votre projet. Enfin, ajoutez la ligne suivante à votre événement de pré-construction:

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

Assurez-vous que BuildDate.cs est inclus dans votre projet. Fonctionne comme un champion sur n'importe quel système d'exploitation!

je fais juste:

File.GetCreationTime(GetType().Assembly.Location)

Vous pouvez utiliser ce projet: https://github.com/dwcullop/BuildInfo

Il utilise T4 pour automatiser l’horodatage de la date de construction. Il existe plusieurs versions (différentes branches), dont une qui vous donne le hachage Git de la branche actuellement extraite, si vous aimez ce genre de chose.

Divulgation: j'ai écrit le module.

Vous pouvez utiliser un événement de post-génération de projet pour écrire un fichier texte dans votre répertoire cible avec la date / heure actuelle. Vous pouvez alors lire la valeur au moment de l'exécution. C'est un petit hacky, mais ça devrait marcher.

Je ne suis pas sûr, mais peut-être que Build Incrementer peut vous aider.

Une approche différente, conviviale pour PCL, consisterait à utiliser une tâche en ligne MSBuild pour remplacer le temps de génération par une chaîne renvoyée par une propriété de l'application. Nous utilisons cette approche avec succès dans une application comportant des projets Xamarin.Forms, Xamarin.Android et Xamarin.iOS.

EDIT:

Simplifié en déplaçant toute la logique dans le fichier SetBuildDate.targets et en utilisant Regex au lieu de chaîne simple, remplacez le fichier afin que le fichier puisse être modifié par chaque construction sans & "; réinitialiser &"; .

La définition de tâche intégrée MSBuild (enregistrée dans un fichier SetBuildDate.targets local du projet Xamarin.Forms pour cet exemple):

<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>

Appel de la tâche en ligne ci-dessus dans le fichier csproj Xamarin.Forms dans la cible 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 propriété FilePath est définie sur un fichier BuildMetadata.cs dans le projet Xamarin.Forms qui contient une classe simple avec une propriété de chaîne BuildDate, dans laquelle sera substituée l'heure de génération:

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

Ajouter ce fichier <=> au projet. Il sera modifié à chaque génération, mais d'une manière qui permette des générations répétées (remplacements répétés). Vous pouvez donc l'inclure ou l'omettre dans le contrôle de source à votre guise.

Une petite mise à jour sur la " New Way " réponse de Jhon.

Vous devez créer le chemin au lieu d'utiliser la chaîne CodeBase lorsque vous utilisez ASP.NET/MVC

    var codeBase = assembly.GetName().CodeBase;
    UriBuilder uri = new UriBuilder(codeBase);
    string path = Uri.UnescapeDataString(uri.Path);

Vous pouvez lancer une étape supplémentaire dans le processus de construction qui écrit un horodatage dans un fichier qui peut ensuite être affiché.

Dans l'onglet Propriétés du projet, consultez l'onglet Événements de construction. Il existe une option pour exécuter une commande pré ou post-build.

J'ai utilisé la suggestion d'Abdurrahim. Cependant, il semblait donner un format de temps étrange et également ajouté l'abréviation du jour dans le cadre de la date de construction; exemple: dim 24/12/2017 13: 21: 05.43. Je n'avais besoin que de la date pour éliminer le reste à l'aide de la sous-chaîne.

Après avoir ajouté le echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt" à l'événement de pré-construction, je viens de faire ce qui suit:

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

La bonne nouvelle est que cela a fonctionné.

S'il s'agit d'une application Windows, vous pouvez simplement utiliser le chemin de l'exécutable de l'application: nouveau System.IO.FileInfo (Application.ExecutablePath) .LastWriteTime.ToString (& "; aaaa.MM.dd &";))

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top