7

I've researched and tried numerous options to try and get this to work, but am not getting anywhere with this unfortunately.

What I am trying to do is set the Date Taken tag (Tag_DateTime) in a JPEG's Exif data from within an Android app. I already have working code to set the Latitude and Longitute tags, but cannot for the life of me get the Date taken tag to set.

Here is the code:

SimpleDateFormat fmt_Exif = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
try {
    ExifInterface exif = new ExifInterface(filePhoto.getPath());

    // Set and save the GPS and time data
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, strLat);
    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, strLong);
    exif.setAttribute(ExifInterface.TAG_DATETIME, fmt_Exif.format(locLatestLocation.getTime()));
    exif.saveAttributes();

} catch (IOException e) {
    e.printStackTrace();
}
  • locLatestLocation - Location being used to get the time in milliseconds.
  • fmt_Exif - SimpleDateFormat used to format the millisecond time into the correct format for the TAG_DateTime Exif tag.
  • strLat & strLong - Populated elsewhere in the correct format to set the Latitude and Longitude tags.

I read in a post somewhere that the tag needs to be written in the milliseconds format, so have tried this too to no avail. In order to confirm my formatting with what is actually stored, I read and outputted the unformatted tag from a jpeg file which has the Date Taken tag, but the output is in exactly the same format as what I am writing to the tag and its still not working.

It might also be worth mentioning that I have looking into the Sanselan class to do this, and due to the complexity and lack of examples would much rather try and get my existing solution working before changing to a completely different one.

Has anyone managed to do this and if so what am I doing wrong??

JohnHenry
  • 505
  • 8
  • 21
  • Did you found any solution? If I try to set the "DateTime" field, there are two such fields in EXIF data after saving... – pbu Sep 19 '12 at 12:44

7 Answers7

9

Android's ExifInterface, annoyingly, silently discards any data it deems to be invalid. Worse yet, the documentation doesn't even mention what valid values might be.

I've also found that if you specify an EXIF attribute that Android can't figure out (IE: it's not one of ExifInterface's TAG_ constants), it will also completely ignore it, and also fail silently.

Phydiux
  • 144
  • 1
  • 4
8

I needed to the same thing just now. I've read this EXIF article from MIT and I got TAG_DATETIME to be written:

exif.setAttribute(ExifInterface.TAG_DATETIME,"2013:06:21 00:00:07");
exif.setAttribute(ExifInterface.TAG_GPS_DATESTAMP,"2013:06:21");
exif.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP,"00:00:07");

Which looked like this previewed:

exif 1

exif 2

Note that this in the EXIF/TIFF and GPS sections only, not the actual Original and Digitized timestamps:

exif 3

I wanted to change the Original and Digitized timestamps too, so tried the JHeader library:

try {
                    JpegHeaders headers = new JpegHeaders(FakeBurst.PICTURE_PATH);
                    App1Header app1Header = headers.getApp1Header();
                    app1Header.setValue(new TagValue(Tag.IMAGEDESCRIPTION,"bla bla bla"));
                    app1Header.setValue(new TagValue(Tag.DATETIMEORIGINAL,"2013:06:21 00:00:07"));
                    app1Header.setValue(new TagValue(Tag.DATETIMEDIGITIZED,"2013:06:21 00:00:07"));
                    headers.save(true);
                    System.out.println(this+" wrote exif timestamp");
                } catch (Exception e) {
                    e.printStackTrace();
                }

with this added in onCreate:

JpegHeaders.preheat();

and it worked:

exif 4

exif 5

I see this post is from December so maybe the Android ExifInterface code I posted above didn't work with that version of the SDK, but I'm guessing the JHeader library approach would work.

George Profenza
  • 50,687
  • 19
  • 144
  • 218
2

I have the same problem with you. When I try to use TAG_DATETIME to save the taken date, it doesn't work, and the original taken_date has been lost. I really don't know the difference between the @hide function of getDateTime() and getGpsDateTime(). It seems the getGpsDateTime() is the taken date. And I'll try the TAG_GPS_DATESTAMP and TAG_GPS_TIMESTAMP.

/**
 * Returns number of milliseconds since Jan. 1, 1970, midnight UTC.
 * Returns -1 if the date time information if not available.
 * @hide
 */
public long getGpsDateTime() {
    String date = mAttributes.get(TAG_GPS_DATESTAMP);
    String time = mAttributes.get(TAG_GPS_TIMESTAMP);
    if (date == null || time == null) return -1;

    String dateTimeString = date + ' ' + time;
    if (dateTimeString == null) return -1;

    ParsePosition pos = new ParsePosition(0);
    try {
        Date datetime = sFormatter.parse(dateTimeString, pos);
        if (datetime == null) return -1;
        return datetime.getTime();
    } catch (IllegalArgumentException ex) {
        return -1;
    }
}
Autobots
  • 1,264
  • 15
  • 14
1

You can try just like they have done in ExifInterface.java

private static SimpleDateFormat sFormatter;

    static {
        sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
        sFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    }

And then update:

exif.setAttribute(ExifInterface.TAG_DATETIME,
                            sFormatter.format(new Date(System.currentTimeMillis())));
Prakash
  • 4,479
  • 30
  • 42
0
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");

exifInterface.setAttribute("DateTimeOriginal", dateTimeFormat.format(date));
exifInterface.setAttribute("DateTimeDigitized", dateTimeFormat.format(date));

That works for me (at least API level 14+)

wilddev
  • 1,904
  • 2
  • 27
  • 45
0

If you use JodaTime library, my example can be useful for you. Note that according to documentation GPS_TIMESTAMP requires UTC format (without local offset).

It works for all fields if they were empty.

val exif = ExifInterface(file.path)
val dateTime = DateTime.now()
val dateTimeStr = dateTime.toString(DateTimeFormat.forPattern("yyyy:MM:dd HH:mm:ss"))
val dateStr = dateTime.toString(DateTimeFormat.forPattern("yyyy:MM:dd"))
val timeUTCStr = dateTime.withZone(DateTimeZone.UTC).toString(DateTimeFormat.forPattern("HH:mm:ss"))
val offsetStr = dateTime.toString(DateTimeFormat.forPattern("ZZ"))
exif.setAttribute(TAG_DATETIME, dateTimeStr)
exif.setAttribute(TAG_DATETIME_DIGITIZED, dateTimeStr)
exif.setAttribute(TAG_DATETIME_ORIGINAL, dateTimeStr)
exif.setAttribute(TAG_GPS_DATESTAMP, dateStr)
exif.setAttribute(TAG_GPS_TIMESTAMP, timeUTCStr)
exif.setAttribute(TAG_OFFSET_TIME, offsetStr)
exif.setAttribute(TAG_OFFSET_TIME_DIGITIZED, offsetStr)
exif.setAttribute(TAG_OFFSET_TIME_ORIGINAL, offsetStr)
exif.saveAttributes()
antaki93
  • 704
  • 7
  • 10
-1

I faced an issue that images from Nexus 6 and Lumia 935 are without CreateDate and DateTimeOriginal fields.

Android and Windows phone save the timestamp also on the filename IMG_20160320_145825.jpg WP_20160328_13_40_42_Pro.jpg

I succeed to fix this issue and add the field running this script:

#! /bin/bash

COUNTER=0
for filename in ./*
do
    case "$filename" in
        *.JPG|*.jpeg|*.jpg)
            COUNTER=$[$COUNTER +1]
            y=${filename:6:4}
            M=${filename:10:2}
            d=${filename:12:2}
            H=${filename:15:2}
            m=${filename:17:2}
            s=${filename:19:2}
            echo "'"$y":"$M":"$d $H":"$m":"$s"'" " --> "$filename
            exiftool -v2 -AllDates="'"$y":"$M":"$d" "$H":"$m":"$s"'" -overwrite_original $filename
            ;;
        *)
            echo $filename 'Not a *.jpg'
            ;;
    esac
done

echo $COUNTER "files updated"

I hope it help someone

coder
  • 23
  • 8