C# 如何解析EXIF日期时间数据

C# 如何解析EXIF日期时间数据,c#,datetime,exif,C#,Datetime,Exif,我正在编写一个C#程序,从JPEG文件中提取EXIFDateTimeOriginal字段,如果该属性在数据中,我需要将其解析为DateTime值 我的密码是: BitmapFrame src = decoder.Frames[ 0 ]; if ( src.Metadata != null ) { BitmapMetadata metaData = (BitmapMetadata) src.Metadata; if ( metaData.ContainsQuery( "/app

我正在编写一个C#程序,从JPEG文件中提取EXIF
DateTimeOriginal
字段,如果该属性在数据中,我需要将其解析为
DateTime

我的密码是:

BitmapFrame src = decoder.Frames[ 0 ];

if ( src.Metadata != null ) {
    BitmapMetadata metaData = (BitmapMetadata) src.Metadata;

    if ( metaData.ContainsQuery( "/app1/{ushort=0}/{ushort=34665}/{ushort=36867}" ) ) {
        object o = metaData.GetQuery( "/app1/{ushort=0}/{ushort=34665}/{ushort=36867}" );

        if ( o != null && o is string ) {
            string originalDate = Convert.ToString( o );

            if ( originalDate != null ) {
                if ( !DateTime.TryParseExact( originalDate.Trim(), "yyyy:MM:dd hh:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out createDate ) ) {
                    // Sets createDate to a default value if the date doesn't parse.
                }
            }
        }
    }
}
但是,调用
TryParseExact
中的格式字符串不起作用,因为代码执行的代码被替换为注释

写格式字符串的正确方法是什么?
DateTimeOriginal
属性中的值格式为YYYY:MM:DD HH:MM:SS。是YYYY、MM和DD说明符之间的冒号让我头疼。他们为什么用冒号

编辑

我尝试将格式说明符字符串更改为“yyyy\:MM\dd hh\:MM:\ss”,但也没有成功。

这是我手头的一个旧程序的代码片段,它的功能与此非常类似:

string dateTakenText;
using (Image photo = Image.FromFile(file.Name))
{
    PropertyItem pi = photo.GetPropertyItem(Program.propertyTagExifDTOrig_);
    ASCIIEncoding enc = new ASCIIEncoding();
    dateTakenText = enc.GetString(pi.Value, 0, pi.Len - 1);
}
if (string.IsNullOrEmpty(dateTakenText))
{
    continue;
}
DateTime dateTaken;
if (!DateTime.TryParseExact(dateTakenText, "yyyy:MM:dd HH:mm:ss",
    CultureInfo.CurrentCulture, DateTimeStyles.None, out dateTaken))
{
    continue;
}
此代码段位于
foreach
循环中,它解释了
continue
关键字的用法

这是我在2002年或2003年写的一个程序的代码,从那时起我就经常使用它;它的工作非常可靠。

这描述了一种解析字符串各个部分的方法,而不是使用DateTime进行解析。解析:

/// <summary>
/// Returns the EXIF Image Data of the Date Taken.
/// </summary>
/// <param name="getImage">Image (If based on a file use Image.FromFile(f);)</param>
/// <returns>Date Taken or Null if Unavailable</returns>
public static DateTime? DateTaken(Image getImage)
{
    int DateTakenValue = 0x9003; //36867;

    if (!getImage.PropertyIdList.Contains(DateTakenValue))
        return null;

    string dateTakenTag = System.Text.Encoding.ASCII.GetString(getImage.GetPropertyItem(DateTakenValue).Value);
    string[] parts = dateTakenTag.Split(':', ' ');
    int year = int.Parse(parts[0]);
    int month = int.Parse(parts[1]);
    int day = int.Parse(parts[2]);
    int hour = int.Parse(parts[3]);
    int minute = int.Parse(parts[4]);
    int second = int.Parse(parts[5]);

    return new DateTime(year, month, day, hour, minute, second);
}
//
///返回拍摄日期的EXIF图像数据。
/// 
///图像(如果基于文件,请使用Image.FromFile(f);)
///获取日期,如果不可用,则为空
公共静态日期时间?拍摄日期(图像获取图像)
{
int DateTakenValue=0x9003;//36867;
如果(!getImage.PropertyIdList.Contains(DateTakenValue))
返回null;
string dateTakenTag=System.Text.Encoding.ASCII.GetString(getImage.GetPropertyItem(DateTakenValue.Value));
string[]parts=dateTakenTag.Split(':','');
int year=int.Parse(部分[0]);
int month=int.Parse(部分[1]);
int day=int.Parse(第[2]部分);
int hour=int.Parse(部分[3]);
int minute=int.Parse(部分[4]);
int second=int.Parse(第[5]部分);
返回新的日期时间(年、月、日、小时、分钟、秒);
}

多亏了马克·希曼和马库斯,我终于明白了这一点。EXIF数据中的时间为24小时/军用时间。字符串中的“hh”格式说明符表示12小时的时间,带有AM/PM。我经过的时间是14点14分,或者下午2点14分。在12小时内,“14”是无效时间


因此,正确的格式说明符是“yyyy:MM:dd HH:MM:ss”。

我最近重写了我在另一个答案中提到的应用程序。这一次,我是用F#写的。这项工作的相关部分如下:

[<Literal>]
let private exifDateTaken = 0x0132

[<Literal>]
let private exifDateTimeOriginal = 0x9003

let private tryParseDate s =
    let res =
        DateTime.TryParseExact(
            s,
            "yyyy:MM:dd HH:mm:ss",
            CultureInfo.InvariantCulture,
            DateTimeStyles.None)
    match res with
    | true, dt -> Some dt
    | _ -> None

let extractDateTaken (fi : FileInfo) =
    let extractExif (img : Image) exif =
        if img.PropertyIdList |> Array.contains exif
        then
            let pi = img.GetPropertyItem exif
            Some (Encoding.ASCII.GetString(pi.Value, 0, pi.Len - 1))
        else None

    use photo = Image.FromFile fi.FullName

    [ exifDateTimeOriginal; exifDateTaken ]
    |> Seq.choose (extractExif photo)
    |> Seq.tryHead
    |> Option.bind tryParseDate
[]
让私有ExifDateTake=0x0132
[]
让私有exifDateTimeOriginal=0x9003
让一等兵来吧=
让我们=
DateTime.TryParseExact(
s
“yyyy:MM:dd HH:MM:ss”,
CultureInfo.InvariantCulture,
DateTimeStyles.None)
匹配
|对,dt->Some dt
|无
let ExtractDateTake(fi:FileInfo)=
让extractExif(img:Image)exif=
如果img.PropertyIdList |>Array.com包含exif
然后
设pi=img.GetPropertyItem exif
一些(Encoding.ASCII.GetString(pi.Value,0,pi.Len-1))
没有别的
使用photo=Image.FromFile fi.FullName
[exifDateTimeOriginal;ExifDateTake]
|>Seq.choose(提取照片)
|>序号tryHead
|>Option.bind tryParseDate

但是嘿,
var
s人,我的眼睛(还有一个
编码.ASCII
):D计算机历史博物馆的东西:)仅供参考,要使用
PropertyIdList.Contains()
必须包括
using System.Linq