@Override
    public PathAttributes toAttributes(final StorageObject object) {
        final PathAttributes attributes = new PathAttributes();
        attributes.setSize(object.getContentLength());
        final Date lastmodified = object.getLastModifiedDate();
        if(lastmodified != null) {
            attributes.setModificationDate(lastmodified.getTime());
        }
        if(StringUtils.isNotBlank(object.getStorageClass())) {
            attributes.setStorageClass(object.getStorageClass());
        }
        else if(object.containsMetadata("storage-class")) {
            attributes.setStorageClass(object.getMetadata("storage-class").toString());
        }
        if(StringUtils.isNotBlank(object.getETag())) {
            attributes.setETag(StringUtils.remove(object.getETag(), '"'));
        }
        // The ETag will only be the MD5 of the object data when the object is stored as plaintext or encrypted
        // using SSE-S3. If the object is encrypted using another method (such as SSE-C or SSE-KMS) the ETag is
        // not the MD5 of the object data.
        attributes.setChecksum(Checksum.parse(object.getETag()));
        if(object instanceof S3Object) {
            if(new HostPreferences(host).getBoolean("s3.listing.versioning.enable")) {
                attributes.setVersionId(((S3Object) object).getVersionId());
            }
        }
        if(object.containsMetadata(METADATA_HEADER_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID)) {
            attributes.setEncryption(new Encryption.Algorithm(object.getServerSideEncryptionAlgorithm(),
                    object.getMetadata(METADATA_HEADER_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID).toString()) {
                @Override
                public String getDescription() {
                    return String.format("SSE-KMS (%s)", key);
                }
            });
        }
        else {
            if(null != object.getServerSideEncryptionAlgorithm()) {
                // AES256
                attributes.setEncryption(new Encryption.Algorithm(object.getServerSideEncryptionAlgorithm(), null) {
                    @Override
                    public String getDescription() {
                        return "SSE-S3 (AES-256)";
                    }
                });
            }
        }
        final Map<String, String> metadata = metadata(object);
        if(!metadata.isEmpty()) {
            attributes.setMetadata(metadata);
        }
        final Long mtime = S3TimestampFeature.fromHeaders(S3TimestampFeature.METADATA_MODIFICATION_DATE,
                Maps.transformValues(object.getMetadataMap(), Object::toString));
        if(-1L != mtime) {
            attributes.setModificationDate(mtime);
        }
        final Long ctime = S3TimestampFeature.fromHeaders(S3TimestampFeature.METADATA_CREATION_DATE,
                Maps.transformValues(object.getMetadataMap(), Object::toString));
        if(-1L != ctime) {
            attributes.setCreationDate(ctime);
        }
        return attributes;
    }
@Test
    public void testMtime() {
        final StorageObject object = new StorageObject();
        object.addMetadata("ETag", "a43c1b0aa53a0c908810c06ab1ff3967");
        object.addMetadata("Mtime", "1647683127.160620746");
        assertEquals(1647683127000L, new S3AttributesAdapter(new Host(new S3Protocol())).toAttributes(object).getModificationDate());
    }