@Override
    public void setTimestamp(final Path file, final TransferStatus status) throws BackgroundException {
        if(file.isVolume()) {
            log.warn(String.format("Skip setting timestamp for %s", file));
            return;
        }
        try {
            if(null != status.getModified()) {
                // The Custom-Time metadata is a user-specified date and time represented in the RFC 3339
                // format YYYY-MM-DD'T'HH:MM:SS.SS'Z' or YYYY-MM-DD'T'HH:MM:SS'Z' when milliseconds are zero.
                final Storage.Objects.Patch request = session.getClient().objects().patch(containerService.getContainer(file).getName(), containerService.getKey(file),
                        new StorageObject().setCustomTime(new DateTime(status.getModified())));
                if(containerService.getContainer(file).attributes().getCustom().containsKey(GoogleStorageAttributesFinderFeature.KEY_REQUESTER_PAYS)) {
                    request.setUserProject(session.getHost().getCredentials().getUsername());
                }
                final StorageObject latest = request.execute();
                status.setResponse(new GoogleStorageAttributesFinderFeature(session).toAttributes(latest));
            }
        }
        catch(IOException e) {
            final BackgroundException failure = new GoogleStorageExceptionMappingService().map("Failure to write attributes of {0}", e, file);
            if(file.isDirectory()) {
                if(failure instanceof NotfoundException) {
                    // No placeholder file may exist but we just have a common prefix
                    return;
                }
            }
            if(failure instanceof InteroperabilityException) {
                if(log.isWarnEnabled()) {
                    log.warn(String.format("Retry rewriting file %s with failure %s writing custom time", file, failure));
                }
                // You cannot remove Custom-Time once it's been set on an object. Additionally, the value for Custom-Time cannot
                // decrease. That is, you cannot set Custom-Time to be an earlier date/time than the existing Custom-Time.
                // You can, however, effectively remove or reset the Custom-Time by rewriting the object.
                status.setResponse(new GoogleStorageCopyFeature(session).copy(file, file, status, new DisabledConnectionCallback(), new DisabledStreamListener()).attributes());
                return;
            }
            throw failure;
        }
    }
@Test
    public void testFindTimesteamp() throws Exception {
        final Path bucket = new Path("cyberduck-test-eu", EnumSet.of(Path.Type.directory, Path.Type.volume));
        final Path test = new GoogleStorageTouchFeature(session).touch(new Path(bucket,
                new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus().withModified(1530305150672L));
        assertEquals(1530305150672L, new GoogleStorageAttributesFinderFeature(session).find(test).getModificationDate());
        final TransferStatus status = new TransferStatus();
        final byte[] content = RandomUtils.nextBytes(1033);
        status.setLength(content.length);
        status.setModified(1530305150673L);
        final HttpResponseOutputStream<StorageObject> out = new GoogleStorageWriteFeature(session).write(test, status, new DisabledConnectionCallback());
        new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), out);
        out.close();
        final PathAttributes response = status.getResponse();
        assertNotNull(response.getETag());
        assertNotNull(response.getVersionId());
        test.withAttributes(response);
        assertEquals(1530305150673L, response.getModificationDate());
        final GoogleStorageTimestampFeature feature = new GoogleStorageTimestampFeature(session);
        // Rewrite object with timestamp earlier than already set
        final TransferStatus rewriteStatus = new TransferStatus().withModified(1530305150672L);
        feature.setTimestamp(test, rewriteStatus);
        final PathAttributes attrAfterRewrite = new GoogleStorageAttributesFinderFeature(session).find(test);
        assertEquals(rewriteStatus.getResponse(), attrAfterRewrite);
        assertEquals(1530305150672L, attrAfterRewrite.getModificationDate());
        assertNotEquals(response.getETag(), attrAfterRewrite.getETag());
        assertNotEquals(response.getVersionId(), attrAfterRewrite.getVersionId());
        final TransferStatus patchStatus = new TransferStatus().withModified(1630305150672L);
        feature.setTimestamp(test, patchStatus);
        assertEquals(1630305150672L, new GoogleStorageAttributesFinderFeature(session).find(test).getModificationDate());
        final PathAttributes attrAfterPatch = new GoogleStorageAttributesFinderFeature(session).find(test);
        assertEquals(patchStatus.getResponse(), attrAfterPatch);
        final String eTagAfterPatch = attrAfterPatch.getETag();
        assertNotEquals(attrAfterRewrite.getETag(), eTagAfterPatch);
        final Path moved = new GoogleStorageMoveFeature(session).move(test, new Path(bucket,
                new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus(), new Delete.DisabledCallback(), new DisabledConnectionCallback());
        assertEquals(1630305150672L, moved.attributes().getModificationDate());
        assertEquals(1630305150672L, new GoogleStorageAttributesFinderFeature(session).find(moved).getModificationDate());
        assertNotEquals(eTagAfterPatch, new GoogleStorageAttributesFinderFeature(session).find(moved).getETag());
        new GoogleStorageDeleteFeature(session).delete(Collections.singletonList(moved), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }