[java-opensaml] branch master updated: JSPT-79 - Review date and time handling for Java 8

Scott Cantor cantor.2 at osu.edu
Fri Mar 1 13:10:02 EST 2019


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch master
in repository java-opensaml.

View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=379adb80c2b00f9c452c131c75c0c8d54e654cdf

The following commit(s) were added to refs/heads/master by this push:
       new  379adb8   JSPT-79 - Review date and time handling for Java 8
379adb8 is described below

commit 379adb80c2b00f9c452c131c75c0c8d54e654cdf
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Mar 1 13:09:57 2019 -0500

    JSPT-79 - Review date and time handling for Java 8
    
    https://issues.shibboleth.net/jira/browse/JSPT-79
---
 opensaml-core/pom.xml                              |  4 --
 .../org/opensaml/core/xml/schema/XSDateTime.java   | 13 ++--
 .../core/xml/schema/impl/XSDateTimeImpl.java       | 23 +++---
 .../core/xml/schema/impl/XSDateTimeMarshaller.java |  2 +-
 .../xml/schema/impl/XSDateTimeUnmarshaller.java    |  8 +--
 .../opensaml/core/xml/schema/XSDateTimeTest.java   | 22 +++---
 opensaml-messaging-api/pom.xml                     |  4 --
 .../opensaml/saml/common/AbstractSAMLObject.java   | 26 +------
 .../saml/common/AbstractSignableSAMLObject.java    | 24 -------
 .../messaging/context/SAMLMessageInfoContext.java  | 11 +--
 ...SAMLMessageInfoContextIssueInstantFunction.java |  7 +-
 .../profile/logic/EntityAttributesPredicate.java   |  6 +-
 .../opensaml/saml/config/SAMLConfiguration.java    | 16 ++---
 .../saml/config/SAMLConfigurationSupport.java      |  4 +-
 .../saml/ext/saml2delrestrict/Delegate.java        |  7 +-
 .../opensaml/saml/ext/saml2mdrpi/Publication.java  |  7 +-
 .../saml/ext/saml2mdrpi/PublicationInfo.java       |  6 +-
 .../saml/ext/saml2mdrpi/RegistrationInfo.java      |  6 +-
 .../resolver/ChainingMetadataResolver.java         | 14 ++--
 .../resolver/ExtendedBatchMetadataResolver.java    |  6 +-
 .../ExtendedRefreshableMetadataResolver.java       |  6 +-
 .../resolver/RefreshableMetadataResolver.java      |  8 +--
 .../org/opensaml/saml/saml1/core/Assertion.java    |  6 +-
 .../saml/saml1/core/AuthenticationStatement.java   |  6 +-
 .../org/opensaml/saml/saml1/core/Conditions.java   | 10 +--
 .../saml/saml1/core/RequestAbstractType.java       |  6 +-
 .../saml/saml1/core/ResponseAbstractType.java      |  7 +-
 .../saml/saml1/profile/SAML1ActionSupport.java     |  5 +-
 .../saml2/assertion/SAML20AssertionValidator.java  | 17 +++--
 .../opensaml/saml/saml2/common/SAML2Support.java   | 33 +++++----
 .../saml/saml2/common/TimeBoundSAMLObject.java     |  7 +-
 .../org/opensaml/saml/saml2/core/Assertion.java    |  6 +-
 .../opensaml/saml/saml2/core/AuthnStatement.java   | 11 +--
 .../org/opensaml/saml/saml2/core/Conditions.java   | 10 +--
 .../opensaml/saml/saml2/core/LogoutRequest.java    |  6 +-
 .../saml/saml2/core/RequestAbstractType.java       |  7 +-
 .../saml/saml2/core/StatusResponseType.java        |  7 +-
 .../saml/saml2/core/SubjectConfirmationData.java   | 11 +--
 .../saml/saml2/profile/SAML2ActionSupport.java     |  5 +-
 .../saml1/profile/SAML1ActionTestingSupport.java   | 13 ++--
 .../saml2/profile/SAML2ActionTestingSupport.java   | 21 +++---
 .../artifact/impl/BasicSAMLArtifactMap.java        |  4 +-
 .../impl/MessageLifetimeSecurityHandler.java       | 12 ++--
 .../impl/MessageReplaySecurityHandler.java         |  9 +--
 .../impl/AddNotOnOrAfterConditionToAssertions.java |  6 +-
 .../ext/saml2delrestrict/impl/DelegateImpl.java    |  8 +--
 .../saml2delrestrict/impl/DelegateMarshaller.java  |  2 +-
 .../impl/DelegateUnmarshaller.java                 |  6 +-
 .../saml/ext/saml2mdrpi/impl/PublicationImpl.java  |  8 +--
 .../ext/saml2mdrpi/impl/PublicationInfoImpl.java   |  8 +--
 .../saml2mdrpi/impl/PublicationInfoMarshaller.java |  5 +-
 .../impl/PublicationInfoUnmarshaller.java          |  6 +-
 .../ext/saml2mdrpi/impl/PublicationMarshaller.java |  8 ++-
 .../saml2mdrpi/impl/PublicationUnmarshaller.java   |  6 +-
 .../ext/saml2mdrpi/impl/RegistrationInfoImpl.java  | 11 +--
 .../impl/RegistrationInfoMarshaller.java           |  5 +-
 .../impl/RegistrationInfoUnmarshaller.java         |  6 +-
 .../filter/impl/RequiredValidUntilFilter.java      | 12 ++--
 .../impl/AbstractBatchMetadataResolver.java        |  4 +-
 .../impl/AbstractDynamicMetadataResolver.java      | 83 ++++++++++------------
 .../impl/AbstractReloadingMetadataResolver.java    | 76 ++++++++++----------
 .../resolver/impl/CompositeMetadataResolver.java   | 14 ++--
 .../impl/FileBackedHTTPMetadataResolver.java       |  4 +-
 .../resolver/impl/FilesystemMetadataResolver.java  |  6 +-
 .../impl/ResourceBackedMetadataResolver.java       |  4 +-
 .../saml/saml1/core/impl/AssertionImpl.java        |  8 +--
 .../saml/saml1/core/impl/AssertionMarshaller.java  |  5 +-
 .../saml1/core/impl/AssertionUnmarshaller.java     |  6 +-
 .../core/impl/AuthenticationStatementImpl.java     |  8 +--
 .../impl/AuthenticationStatementMarshaller.java    |  2 +-
 .../impl/AuthenticationStatementUnmarshaller.java  |  7 +-
 .../saml/saml1/core/impl/ConditionsImpl.java       | 14 ++--
 .../saml/saml1/core/impl/ConditionsMarshaller.java |  4 +-
 .../saml1/core/impl/ConditionsUnmarshaller.java    |  8 +--
 .../saml1/core/impl/RequestAbstractTypeImpl.java   |  8 +--
 .../core/impl/RequestAbstractTypeMarshaller.java   |  2 +-
 .../core/impl/RequestAbstractTypeUnmarshaller.java |  7 +-
 .../saml1/core/impl/ResponseAbstractTypeImpl.java  | 10 +--
 .../core/impl/ResponseAbstractTypeMarshaller.java  |  2 +-
 .../impl/ResponseAbstractTypeUnmarshaller.java     |  6 +-
 .../saml/saml1/profile/impl/AddResponseShell.java  |  5 +-
 .../impl/AbstractSubjectConfirmationValidator.java | 13 ++--
 .../binding/decoding/impl/HTTPArtifactDecoder.java |  5 +-
 .../saml/saml2/core/impl/AssertionImpl.java        | 26 +++----
 .../saml/saml2/core/impl/AssertionMarshaller.java  |  2 +-
 .../saml2/core/impl/AssertionUnmarshaller.java     |  6 +-
 .../saml/saml2/core/impl/AuthnStatementImpl.java   | 14 ++--
 .../saml2/core/impl/AuthnStatementMarshaller.java  |  4 +-
 .../core/impl/AuthnStatementUnmarshaller.java      |  9 ++-
 .../saml/saml2/core/impl/ConditionsImpl.java       | 14 ++--
 .../saml/saml2/core/impl/ConditionsMarshaller.java |  4 +-
 .../saml2/core/impl/ConditionsUnmarshaller.java    |  8 +--
 .../saml/saml2/core/impl/LogoutRequestImpl.java    |  8 +--
 .../saml2/core/impl/LogoutRequestMarshaller.java   |  2 +-
 .../saml2/core/impl/LogoutRequestUnmarshaller.java |  6 +-
 .../saml2/core/impl/RequestAbstractTypeImpl.java   | 26 +++----
 .../core/impl/RequestAbstractTypeMarshaller.java   |  2 +-
 .../core/impl/RequestAbstractTypeUnmarshaller.java |  6 +-
 .../saml2/core/impl/StatusResponseTypeImpl.java    | 14 ++--
 .../core/impl/StatusResponseTypeMarshaller.java    |  2 +-
 .../core/impl/StatusResponseTypeUnmarshaller.java  |  6 +-
 .../core/impl/SubjectConfirmationDataImpl.java     | 14 ++--
 .../impl/SubjectConfirmationDataMarshaller.java    |  5 +-
 .../impl/SubjectConfirmationDataUnmarshaller.java  |  8 +--
 .../metadata/impl/AffiliationDescriptorImpl.java   | 11 ++-
 .../impl/AffiliationDescriptorMarshaller.java      |  2 +-
 .../impl/AffiliationDescriptorUnmarshaller.java    |  6 +-
 .../metadata/impl/EntitiesDescriptorImpl.java      | 11 ++-
 .../impl/EntitiesDescriptorMarshaller.java         |  2 +-
 .../impl/EntitiesDescriptorUnmarshaller.java       |  6 +-
 .../saml2/metadata/impl/EntityDescriptorImpl.java  | 11 ++-
 .../metadata/impl/EntityDescriptorMarshaller.java  |  2 +-
 .../impl/EntityDescriptorUnmarshaller.java         |  6 +-
 .../saml2/metadata/impl/RoleDescriptorImpl.java    | 11 ++-
 .../metadata/impl/RoleDescriptorMarshaller.java    |  2 +-
 .../metadata/impl/RoleDescriptorUnmarshaller.java  |  5 +-
 .../profile/impl/AbstractResponseShellAction.java  |  5 +-
 .../saml2/profile/impl/AddStatusResponseShell.java |  5 +-
 .../impl/AddSubjectConfirmationToSubjects.java     |  4 +-
 .../impl/MessageLifetimeSecurityHandlerTest.java   | 16 ++---
 ...LOutboundProtocolMessageSigningHandlerTest.java |  6 +-
 .../context/SAMLMessageInfoContextTest.java        |  8 +--
 .../AddNotOnOrAfterConditionToAssertionsTest.java  |  8 +--
 .../ext/saml2delrestrict/impl/DelegateTest.java    | 11 +--
 .../ext/saml2mdattr/impl/EntityAttributesTest.java |  9 +--
 .../ext/saml2mdrpi/impl/PublicationInfoTest.java   |  6 +-
 .../saml/ext/saml2mdrpi/impl/PublicationTest.java  |  6 +-
 .../ext/saml2mdrpi/impl/RegistrationInfoTest.java  |  6 +-
 .../filter/impl/RequiredValidUntilTest.java        |  5 +-
 .../impl/FileBackedHTTPMetadataResolverTest.java   | 27 ++++---
 .../binding/encoding/impl/HTTPPostEncoderTest.java |  4 +-
 .../encoding/impl/HTTPSOAP11EncoderTest.java       |  4 +-
 .../saml/saml1/core/impl/AssertionTest.java        | 12 ++--
 .../core/impl/AuthenticationStatementTest.java     | 12 ++--
 .../saml/saml1/core/impl/ConditionsTest.java       | 21 +++---
 .../opensaml/saml/saml1/core/impl/RequestTest.java | 11 +--
 .../saml/saml1/core/impl/ResponseTest.java         | 12 ++--
 .../assertion/BaseAssertionValidationTest.java     | 17 ++---
 .../assertion/SAML20AssertionValidatorTest.java    | 11 +--
 .../AbstractSubjectConfirmationValidatorTest.java  | 11 +--
 .../binding/encoding/impl/HTTPPostEncoderTest.java |  6 +-
 .../impl/HTTPPostSimpleSignEncoderTest.java        |  8 +--
 .../impl/HTTPRedirectDeflateEncoderTest.java       | 10 +--
 .../encoding/impl/HTTPSOAP11EncoderTest.java       |  4 +-
 .../opensaml/saml/saml2/core/AuthnRequestTest.java |  9 +--
 .../saml2/core/ResponseSuccessAuthnAttribTest.java | 25 +++----
 .../saml/saml2/core/SignedAssertionTest.java       |  4 +-
 .../saml/saml2/core/impl/AssertionTest.java        | 13 ++--
 .../saml/saml2/core/impl/AuthnStatementTest.java   | 19 ++---
 .../saml/saml2/core/impl/ConditionsTest.java       | 19 ++---
 .../core/impl/KeyInfoConfirmationDataTypeTest.java | 17 ++---
 .../saml/saml2/core/impl/LogoutRequestTest.java    |  9 +--
 .../saml/saml2/core/impl/RequestTestBase.java      |  9 +--
 .../saml2/core/impl/StatusResponseTestBase.java    | 11 +--
 .../core/impl/SubjectConfirmationDataTest.java     | 19 ++---
 .../encryption/DecryptionPlusSigningTest.java      |  4 +-
 .../metadata/impl/AffiliationDescriptorTest.java   | 12 ++--
 .../impl/AuthnAuthorityDescriptorTest.java         | 12 ++--
 .../metadata/impl/EntitiesDescriptorTest.java      | 13 ++--
 .../saml2/metadata/impl/EntityDescriptorTest.java  | 12 ++--
 .../saml2/metadata/impl/IDPSSODescriptorTest.java  |  7 +-
 .../saml2/metadata/impl/PDPDescriptorTest.java     |  7 +-
 .../saml2/metadata/impl/SPSSODescriptorTest.java   |  7 +-
 .../soap/wssecurity/AttributedDateTime.java        | 18 ++---
 .../wssecurity/messaging/WSSecurityContext.java    | 16 ++---
 .../wssecurity/impl/AttributedDateTimeImpl.java    | 21 +++---
 .../messaging/impl/AddTimestampHandler.java        | 37 +++++-----
 .../wssecurity/impl/WSSecurityObjectsTestCase.java | 15 ++--
 .../messaging/impl/AddTimestampHandlerTest.java    | 50 +++++--------
 .../soap/wstrust/impl/WSTrustObjectsTestCase.java  |  8 ++-
 opensaml-storage-api/pom.xml                       |  4 --
 .../storage/annotation/AnnotationSupport.java      | 12 ++--
 172 files changed, 854 insertions(+), 938 deletions(-)

diff --git a/opensaml-core/pom.xml b/opensaml-core/pom.xml
index 8e3d3a0..b37c603 100644
--- a/opensaml-core/pom.xml
+++ b/opensaml-core/pom.xml
@@ -23,10 +23,6 @@
     <dependencies>
         <!-- Compile Dependencies -->
         <dependency>
-            <groupId>joda-time</groupId>
-            <artifactId>joda-time</artifactId>
-        </dependency>
-        <dependency>
             <groupId>io.dropwizard.metrics</groupId>
             <artifactId>metrics-core</artifactId>
         </dependency>
diff --git a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/XSDateTime.java b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/XSDateTime.java
index a0b2363..76961e2 100644
--- a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/XSDateTime.java
+++ b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/XSDateTime.java
@@ -17,14 +17,15 @@
 
 package org.opensaml.core.xml.schema;
 
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.xml.namespace.QName;
 
 import net.shibboleth.utilities.java.support.xml.XMLConstants;
 
-import org.joda.time.DateTime;
-import org.joda.time.format.DateTimeFormatter;
 import org.opensaml.core.xml.XMLObject;
 
 /**
@@ -43,22 +44,20 @@ public interface XSDateTime extends XMLObject {
      * 
      * @return the dateTime value
      */
-    @Nullable public DateTime getValue();
+    @Nullable public Instant getValue();
     
     /**
      * Sets the dateTime value.
      * 
      * @param newValue the dateTime value
      */
-    public void setValue(@Nullable final DateTime newValue);
+    public void setValue(@Nullable final Instant newValue);
     
     /**
      * Get the {@link DateTimeFormatter} to be used when stringifying
      * the {@link DateTime} value.
      * 
-     * <p>Defaults to the formatter constructed by calling:
-     * <code>ISODateTimeFormat.dateTime().withChronology(org.joda.time.chrono.ISOChronology.getInstanceUTC())</code>
-     * </p>
+     * <p>Defaults to {@link DateTimeFormatter.ISO_INSTANT}.</p>
      * 
      * @return the currently configured formatter
      */
diff --git a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeImpl.java b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeImpl.java
index 761a12b..9fc35e5 100644
--- a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeImpl.java
+++ b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeImpl.java
@@ -17,15 +17,17 @@
 
 package org.opensaml.core.xml.schema.impl;
 
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
 import java.util.Collections;
 import java.util.List;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.ISODateTimeFormat;
 import org.opensaml.core.xml.AbstractXMLObject;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.schema.XSDateTime;
@@ -37,7 +39,7 @@ import org.opensaml.core.xml.schema.XSDateTime;
 public class XSDateTimeImpl extends AbstractXMLObject implements XSDateTime {
     
     /** Value of this dateTime element. */
-    private DateTime value;
+    private Instant value;
     
     /** The date time formatter to use. */
     private DateTimeFormatter formatter;
@@ -49,18 +51,19 @@ public class XSDateTimeImpl extends AbstractXMLObject implements XSDateTime {
      * @param elementLocalName the local name of the XML element this Object represents
      * @param namespacePrefix the prefix for the given namespace
      */
-    protected XSDateTimeImpl(final String namespaceURI, final String elementLocalName, final String namespacePrefix) {
+    protected XSDateTimeImpl(@Nullable final String namespaceURI, @Nonnull @NotEmpty final String elementLocalName,
+            @Nullable final String namespacePrefix) {
         super(namespaceURI, elementLocalName, namespacePrefix);
-        formatter = ISODateTimeFormat.dateTime().withChronology(ISOChronology.getInstanceUTC());
+        formatter = DateTimeFormatter.ISO_INSTANT;
     }
     
     /** {@inheritDoc} */
-    public DateTime getValue() {
+    public Instant getValue() {
         return value;
     }
 
     /** {@inheritDoc} */
-    public void setValue(final DateTime newValue) {
+    public void setValue(final Instant newValue) {
         value = prepareForAssignment(value, newValue);
     }
 
@@ -79,4 +82,4 @@ public class XSDateTimeImpl extends AbstractXMLObject implements XSDateTime {
         formatter = Constraint.isNotNull(newFormatter, "The formatter cannot be null");
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeMarshaller.java b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeMarshaller.java
index 64e44f4..cd805b6 100644
--- a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeMarshaller.java
+++ b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeMarshaller.java
@@ -38,7 +38,7 @@ public class XSDateTimeMarshaller extends BaseXMLObjectMarshaller {
             throws MarshallingException {
         final XSDateTime xsDateTime = (XSDateTime) xmlObject;
         
-        ElementSupport.appendTextContent(domElement, xsDateTime.getDateTimeFormatter().print(xsDateTime.getValue()));
+        ElementSupport.appendTextContent(domElement, xsDateTime.getDateTimeFormatter().format(xsDateTime.getValue()));
     }
 
 }
diff --git a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeUnmarshaller.java b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeUnmarshaller.java
index 159d54e..5503047 100644
--- a/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeUnmarshaller.java
+++ b/opensaml-core/src/main/java/org/opensaml/core/xml/schema/impl/XSDateTimeUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.core.xml.schema.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.BaseXMLObjectUnmarshaller;
 import org.opensaml.core.xml.schema.XSDateTime;
@@ -35,7 +35,7 @@ public class XSDateTimeUnmarshaller extends BaseXMLObjectUnmarshaller{
     protected void processElementContent(final XMLObject xmlObject, final String elementContent) {
         final XSDateTime xsDateTime = (XSDateTime) xmlObject;
         
-        xsDateTime.setValue(new DateTime(elementContent).withChronology(ISOChronology.getInstanceUTC()));
+        xsDateTime.setValue(Instant.from(xsDateTime.getDateTimeFormatter().parse(elementContent)));
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-core/src/test/java/org/opensaml/core/xml/schema/XSDateTimeTest.java b/opensaml-core/src/test/java/org/opensaml/core/xml/schema/XSDateTimeTest.java
index b0ccaf1..f5a95ba 100644
--- a/opensaml-core/src/test/java/org/opensaml/core/xml/schema/XSDateTimeTest.java
+++ b/opensaml-core/src/test/java/org/opensaml/core/xml/schema/XSDateTimeTest.java
@@ -20,12 +20,14 @@ package org.opensaml.core.xml.schema;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
 import javax.xml.namespace.QName;
 
 import net.shibboleth.utilities.java.support.xml.XMLParserException;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.core.xml.XMLObjectBuilder;
 import org.opensaml.core.xml.io.Marshaller;
@@ -41,12 +43,13 @@ import org.w3c.dom.Document;
 public class XSDateTimeTest extends XMLObjectBaseTestCase {
     
     private QName expectedXMLObjectQName;
-    private DateTime expectedValue;
+    private Instant expectedValue;
     
     @BeforeMethod
     protected void setUp() throws Exception{
         expectedXMLObjectQName = new QName("urn:example.org:foo", "bar", "foo");
-        expectedValue = new DateTime(2010, 04, 05, 18, 52, 42, 790, ISOChronology.getInstanceUTC());
+        //expectedValue = new DateTime(2010, 04, 05, 18, 52, 42, 790, ISOChronology.getInstanceUTC());
+        expectedValue = Instant.parse("2010-04-05T18:52:42.790Z");
     }
 
     /**
@@ -88,8 +91,7 @@ public class XSDateTimeTest extends XMLObjectBaseTestCase {
         Assert.assertEquals(xsDateTime.getElementQName(), expectedXMLObjectQName, "Unexpected XSDate QName");
         Assert.assertEquals(xsDateTime.getSchemaType(), XSDateTime.TYPE_NAME, "Unexpected XSDateTime schema type");
         // For equivalence testing of DateTime instances, need to make sure are in the same chronology
-        Assert.assertEquals(xsDateTime.getValue().withChronology(ISOChronology.getInstanceUTC()), expectedValue, 
-                "Unexpected value of XSDateTime");
+        Assert.assertEquals(xsDateTime.getValue(), expectedValue, "Unexpected value of XSDateTime");
     }
     
     /**
@@ -110,8 +112,7 @@ public class XSDateTimeTest extends XMLObjectBaseTestCase {
         Assert.assertEquals(xsDateTime.getElementQName(), expectedXMLObjectQName, "Unexpected XSDate QName");
         Assert.assertEquals(xsDateTime.getSchemaType(), XSDateTime.TYPE_NAME, "Unexpected XSDateTime schema type");
         // For equivalence testing of DateTime instances, need to make sure are in the same chronology
-        Assert.assertEquals(xsDateTime.getValue().withChronology(ISOChronology.getInstanceUTC()), expectedValue, 
-                "Unexpected value of XSDateTime");
+        Assert.assertEquals(xsDateTime.getValue(), expectedValue, "Unexpected value of XSDateTime");
     }
     
     /**
@@ -123,7 +124,7 @@ public class XSDateTimeTest extends XMLObjectBaseTestCase {
     @Test
     public void testUnmarshallNoFractional() throws XMLParserException, UnmarshallingException{
         String testDocumentLocation = "/org/opensaml/core/xml/schema/xsDateTime-nofractional.xml";
-        expectedValue = expectedValue.withMillisOfSecond(0);
+        expectedValue = expectedValue.truncatedTo(ChronoUnit.SECONDS);
         
         Document document = parserPool.parse(XSDateTimeTest.class.getResourceAsStream(testDocumentLocation));
 
@@ -133,7 +134,6 @@ public class XSDateTimeTest extends XMLObjectBaseTestCase {
         Assert.assertEquals(xsDateTime.getElementQName(), expectedXMLObjectQName, "Unexpected XSDate QName");
         Assert.assertEquals(xsDateTime.getSchemaType(), XSDateTime.TYPE_NAME, "Unexpected XSDateTime schema type");
         // For equivalence testing of DateTime instances, need to make sure are in the same chronology
-        Assert.assertEquals(xsDateTime.getValue().withChronology(ISOChronology.getInstanceUTC()), expectedValue, 
-                "Unexpected value of XSDateTime");
+        Assert.assertEquals(xsDateTime.getValue(), expectedValue, "Unexpected value of XSDateTime");
     }
 }
\ No newline at end of file
diff --git a/opensaml-messaging-api/pom.xml b/opensaml-messaging-api/pom.xml
index be8c454..5991922 100644
--- a/opensaml-messaging-api/pom.xml
+++ b/opensaml-messaging-api/pom.xml
@@ -29,10 +29,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>joda-time</groupId>
-            <artifactId>joda-time</artifactId>
-        </dependency>
-        <dependency>
             <groupId>${httpclient.groupId}</groupId>
             <artifactId>httpclient</artifactId>
         </dependency>
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSAMLObject.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSAMLObject.java
index ba6ff11..ce9e98e 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSAMLObject.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSAMLObject.java
@@ -20,12 +20,12 @@ package org.opensaml.saml.common;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.opensaml.core.xml.AbstractXMLObject;
 
 /**
  * An abstract implementation of SAMLObject.
+ * 
+ * TODO: this is a no-op base class now
  */
 public abstract class AbstractSAMLObject extends AbstractXMLObject {
 
@@ -55,26 +55,4 @@ public abstract class AbstractSAMLObject extends AbstractXMLObject {
         return super.hashCode();
     }
 
-    /**
-     * A helper function for derived classes that checks to see if the old and new value are equal and if so releases
-     * the cached dom. Derived classes are expected to use this thus: <code>
-     *   this.foo = prepareForAssignment(this.foo, foo);
-     *   </code>
-     * 
-     * This method will do a (null) safe compare of the objects and will also invalidate the DOM if appropriate
-     * 
-     * @param oldValue - current value
-     * @param newValue - proposed new value
-     * 
-     * @return The value to assign to the saved Object.
-     */
-    @Nullable protected DateTime prepareForAssignment(@Nullable final DateTime oldValue,
-            @Nullable final DateTime newValue) {
-        DateTime utcValue = null;
-        if (newValue != null) {
-            utcValue = newValue.withZone(DateTimeZone.UTC);
-        }
-
-        return super.prepareForAssignment(oldValue, utcValue);
-    }
 }
\ No newline at end of file
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSignableSAMLObject.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSignableSAMLObject.java
index c8f7353..e5dbe79 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSignableSAMLObject.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/AbstractSignableSAMLObject.java
@@ -22,8 +22,6 @@ import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.opensaml.xmlsec.signature.AbstractSignableXMLObject;
 import org.opensaml.xmlsec.signature.Signature;
 
@@ -73,26 +71,4 @@ public abstract class AbstractSignableSAMLObject extends AbstractSignableXMLObje
         super.setSignature(newSignature);
     }
 
-    /**
-     * A helper function for derived classes that checks to see if the old and new value are equal and if so releases
-     * the cached dom. Derived classes are expected to use this thus: <code>
-     *   this.foo = prepareForAssignment(this.foo, foo);
-     *   </code>
-     * 
-     * This method will do a (null) safe compare of the objects and will also invalidate the DOM if appropriate
-     * 
-     * @param oldValue - current value
-     * @param newValue - proposed new value
-     * 
-     * @return The value to assign to the saved Object
-     */
-    @Nullable protected DateTime prepareForAssignment(@Nullable final DateTime oldValue,
-            @Nullable final DateTime newValue) {
-        DateTime utcValue = null;
-        if (newValue != null) {
-            utcValue = newValue.withZone(DateTimeZone.UTC);
-        }
-
-        return super.prepareForAssignment(oldValue, utcValue);
-    }
 }
\ No newline at end of file
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContext.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContext.java
index 825af30..51a684f 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContext.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContext.java
@@ -17,9 +17,10 @@
 
 package org.opensaml.saml.common.messaging.context;
 
+import java.time.Instant;
+
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.opensaml.messaging.context.BaseContext;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.saml.common.SAMLObject;
@@ -46,7 +47,7 @@ public final class SAMLMessageInfoContext extends BaseContext {
     @Nullable @NotEmpty private String messageId;
 
     /** The issue instant of the message. */
-    @Nullable private DateTime issueInstant;
+    @Nullable private Instant issueInstant;
 
     /**
      * Gets the ID of the message.
@@ -74,7 +75,7 @@ public final class SAMLMessageInfoContext extends BaseContext {
      * 
      * @return issue instant of the message
      */
-    @Nullable public DateTime getMessageIssueInstant() {
+    @Nullable public Instant getMessageIssueInstant() {
         if (issueInstant == null) {
             issueInstant = resolveIssueInstant();
         }
@@ -86,7 +87,7 @@ public final class SAMLMessageInfoContext extends BaseContext {
      * 
      * @param messageIssueInstant issue instant of the message
      */
-    public void setMessageIssueInstant(@Nullable final DateTime messageIssueInstant) {
+    public void setMessageIssueInstant(@Nullable final Instant messageIssueInstant) {
         issueInstant = messageIssueInstant;
     }
 
@@ -127,7 +128,7 @@ public final class SAMLMessageInfoContext extends BaseContext {
      * 
      * @return the message issue instant, or null if it can not be resolved
      */
-    @Nullable protected DateTime resolveIssueInstant() {
+    @Nullable protected Instant resolveIssueInstant() {
         final SAMLObject samlMessage = resolveSAMLMessage();
         //SAML 2 Request
         if (samlMessage instanceof org.opensaml.saml.saml2.core.RequestAbstractType) {
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/navigate/SAMLMessageInfoContextIssueInstantFunction.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/navigate/SAMLMessageInfoContextIssueInstantFunction.java
index 7402ed8..d03167b 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/navigate/SAMLMessageInfoContextIssueInstantFunction.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/messaging/context/navigate/SAMLMessageInfoContextIssueInstantFunction.java
@@ -17,18 +17,19 @@
 
 package org.opensaml.saml.common.messaging.context.navigate;
 
+import java.time.Instant;
+
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import org.opensaml.saml.common.messaging.context.SAMLMessageInfoContext;
 
 /** {@link ContextDataLookupFunction} that returns {@link SAMLMessageInfoContext#getMessageIssueInstant()}. */
 public class SAMLMessageInfoContextIssueInstantFunction
-        implements ContextDataLookupFunction<SAMLMessageInfoContext,DateTime> {
+        implements ContextDataLookupFunction<SAMLMessageInfoContext,Instant> {
 
     /** {@inheritDoc} */
-    @Nullable public DateTime apply(@Nullable final SAMLMessageInfoContext input) {
+    @Nullable public Instant apply(@Nullable final SAMLMessageInfoContext input) {
         if (input != null) {
             return input.getMessageIssueInstant();
         } else {
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/profile/logic/EntityAttributesPredicate.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/profile/logic/EntityAttributesPredicate.java
index 43d1469..7d3118e 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/common/profile/logic/EntityAttributesPredicate.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/common/profile/logic/EntityAttributesPredicate.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.common.profile.logic;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -26,7 +27,6 @@ import java.util.regex.Pattern;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.schema.XSAny;
 import org.opensaml.core.xml.schema.XSBase64Binary;
@@ -420,9 +420,9 @@ public class EntityAttributesPredicate implements Predicate<EntityDescriptor> {
             } else if (object instanceof XSInteger) {
                 toMatch = ((XSInteger) object).getValue().toString();
             } else if (object instanceof XSDateTime) {
-                final DateTime dt = ((XSDateTime) object).getValue();
+                final Instant dt = ((XSDateTime) object).getValue();
                 if (dt != null) {
-                    toMatch = ((XSDateTime) object).getDateTimeFormatter().print(dt);
+                    toMatch = ((XSDateTime) object).getDateTimeFormatter().format(dt);
                 }
             } else if (object instanceof XSBase64Binary) {
                 toMatch = ((XSBase64Binary) object).getValue();
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfiguration.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfiguration.java
index 32363f7..94a7b33 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfiguration.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfiguration.java
@@ -17,6 +17,8 @@
 
 package org.opensaml.saml.config;
 
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -26,9 +28,6 @@ import java.util.function.Function;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.chrono.ISOChronology;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
 import org.opensaml.saml.saml1.binding.artifact.SAML1ArtifactBuilderFactory;
 import org.opensaml.saml.saml2.binding.artifact.SAML2ArtifactBuilderFactory;
 
@@ -54,9 +53,6 @@ public class SAMLConfiguration {
     /** Lowercase string function. */
     private static Function<String, String> lowercaseFunction = new LowercaseFunction();
 
-    /** Date format in SAML object, default is yyyy-MM-dd'T'HH:mm:ss.SSS'Z'. */
-    private static String defaultDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
-
     /** Formatter used to write dates. */
     private DateTimeFormatter dateFormatter;
 
@@ -80,14 +76,13 @@ public class SAMLConfiguration {
     }
 
     /**
-     * Gets the date format used to string'ify SAML's {@link org.joda.time.DateTime} objects.
+     * Gets the date format used to string'ify SAML's date/time information.
      * 
      * @return date format used to string'ify date objects
      */
     public DateTimeFormatter getSAMLDateFormatter() {
         if (dateFormatter == null) {
-            final DateTimeFormatter formatter = DateTimeFormat.forPattern(defaultDateFormat);
-            dateFormatter = formatter.withChronology(ISOChronology.getInstanceUTC());
+            dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(ZoneOffset.UTC);
         }
         
         return dateFormatter;
@@ -101,8 +96,7 @@ public class SAMLConfiguration {
      * @param format date format used to string'ify date objects
      */
     public void setSAMLDateFormat(final String format) {
-        final DateTimeFormatter formatter = DateTimeFormat.forPattern(format);
-        dateFormatter = formatter.withChronology(ISOChronology.getInstanceUTC());
+        dateFormatter = DateTimeFormatter.ofPattern(format).withZone(ZoneOffset.UTC);
     }
 
     /**
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfigurationSupport.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfigurationSupport.java
index 2f2ce2e..0630f5b 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfigurationSupport.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/config/SAMLConfigurationSupport.java
@@ -17,9 +17,9 @@
 
 package org.opensaml.saml.config;
 
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 
-import org.joda.time.format.DateTimeFormatter;
 import org.opensaml.core.config.ConfigurationService;
 import org.opensaml.saml.saml1.binding.artifact.SAML1ArtifactBuilderFactory;
 import org.opensaml.saml.saml2.binding.artifact.SAML2ArtifactBuilderFactory;
@@ -35,7 +35,7 @@ public final class SAMLConfigurationSupport {
     private SAMLConfigurationSupport() {}
 
     /**
-     * Gets the date format used to string'ify SAML's {@link org.joda.time.DateTime} objects.
+     * Gets the date format used to string'ify SAML's date/time objects.
      * 
      * @return date format used to string'ify date objects
      */
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2delrestrict/Delegate.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2delrestrict/Delegate.java
index dad85f0..cc0fd8f 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2delrestrict/Delegate.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2delrestrict/Delegate.java
@@ -17,9 +17,10 @@
 
 package org.opensaml.saml.ext.saml2delrestrict;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.core.BaseID;
@@ -99,14 +100,14 @@ public interface Delegate extends SAMLObject {
      * 
      * @return the delegation instant
      */
-    public DateTime getDelegationInstant();
+    public Instant getDelegationInstant();
     
     /**
      * Set the delegation instant attribute value.
      * 
      * @param newInstant the new delegation instant
      */
-    public void setDelegationInstant(DateTime newInstant);
+    public void setDelegationInstant(Instant newInstant);
     
     /**
      * Get the confirmation method attribute value.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/Publication.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/Publication.java
index d65656b..7ea0c0d 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/Publication.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/Publication.java
@@ -17,9 +17,10 @@
 
 package org.opensaml.saml.ext.saml2mdrpi;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
@@ -73,14 +74,14 @@ public interface Publication extends SAMLObject {
      * 
      * @return the creation instant
      */
-    public DateTime getCreationInstant();
+    public Instant getCreationInstant();
 
     /**
      * Set the creation instant.
      * 
      * @param dateTime the instant
      */
-    public void setCreationInstant(DateTime dateTime);
+    public void setCreationInstant(Instant dateTime);
 
     /**
      * Get the publicationId.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/PublicationInfo.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/PublicationInfo.java
index d375458..bd0d3f7 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/PublicationInfo.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/PublicationInfo.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.ext.saml2mdrpi;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
@@ -75,14 +75,14 @@ public interface PublicationInfo extends SAMLObject {
      * 
      * @return the creation instant
      */
-    public DateTime getCreationInstant();
+    public Instant getCreationInstant();
 
     /**
      * Set the creation instant.
      * 
      * @param dateTime the instant
      */
-    public void setCreationInstant(DateTime dateTime);
+    public void setCreationInstant(Instant dateTime);
 
     /**
      * Get the publicationId.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/RegistrationInfo.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/RegistrationInfo.java
index 5773807..cf6d50a 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/RegistrationInfo.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/ext/saml2mdrpi/RegistrationInfo.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.ext.saml2mdrpi;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
@@ -72,14 +72,14 @@ public interface RegistrationInfo extends SAMLObject {
      * 
      * @return the registration instant
      */
-    public DateTime getRegistrationInstant();
+    public Instant getRegistrationInstant();
 
     /**
      * Set the registration instant.
      * 
      * @param dateTime the instant
      */
-    public void setRegistrationInstant(DateTime dateTime);
+    public void setRegistrationInstant(Instant dateTime);
 
     /**
      * Get the {@link RegistrationPolicy}s.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ChainingMetadataResolver.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ChainingMetadataResolver.java
index 06cad12..559eadf 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ChainingMetadataResolver.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ChainingMetadataResolver.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.metadata.resolver;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -34,7 +35,6 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
 import org.opensaml.saml.saml2.metadata.EntityDescriptor;
 import org.slf4j.Logger;
@@ -180,11 +180,11 @@ public class ChainingMetadataResolver extends AbstractIdentifiableInitializableC
 
     /** {@inheritDoc} */
     @Override
-    @Nullable public DateTime getLastUpdate() {
-        DateTime ret = null;
+    @Nullable public Instant getLastUpdate() {
+        Instant ret = null;
         for (final MetadataResolver resolver : resolvers) {
             if (resolver instanceof RefreshableMetadataResolver) {
-                final DateTime lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate();
+                final Instant lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate();
                 if (ret == null || ret.isBefore(lastUpdate)) {
                     ret = lastUpdate;
                 }
@@ -196,11 +196,11 @@ public class ChainingMetadataResolver extends AbstractIdentifiableInitializableC
 
     /** {@inheritDoc} */
     @Override
-    @Nullable public DateTime getLastRefresh() {
-        DateTime ret = null;
+    @Nullable public Instant getLastRefresh() {
+        Instant ret = null;
         for (final MetadataResolver resolver : resolvers) {
             if (resolver instanceof RefreshableMetadataResolver) {
-                final DateTime lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh();
+                final Instant lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh();
                 if (ret == null || ret.isBefore(lastRefresh)) {
                     ret = lastRefresh;
                 }
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedBatchMetadataResolver.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedBatchMetadataResolver.java
index 2f37f2f..6552f40 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedBatchMetadataResolver.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedBatchMetadataResolver.java
@@ -17,9 +17,9 @@
 
 package org.opensaml.saml.metadata.resolver;
 
-import javax.annotation.Nullable;
+import java.time.Instant;
 
-import org.joda.time.DateTime;
+import javax.annotation.Nullable;
 
 /**
  * Extended {@link BatchMetadataResolver}.
@@ -33,7 +33,7 @@ public interface ExtendedBatchMetadataResolver extends BatchMetadataResolver {
      *
      * @return the validUntil date/time of the root element, or null if not available
      */
-    @Nullable public DateTime getRootValidUntil();
+    @Nullable public Instant getRootValidUntil();
 
     /**
      * Get the validity state of the metadata batch root element, as determined in an implementation-specific manner.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedRefreshableMetadataResolver.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedRefreshableMetadataResolver.java
index 471df43..f87eb33 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedRefreshableMetadataResolver.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/ExtendedRefreshableMetadataResolver.java
@@ -17,9 +17,9 @@
 
 package org.opensaml.saml.metadata.resolver;
 
-import javax.annotation.Nullable;
+import java.time.Instant;
 
-import org.joda.time.DateTime;
+import javax.annotation.Nullable;
 
 /**
  * Extended {@link RefreshableMetadataResolver}.
@@ -33,7 +33,7 @@ public interface ExtendedRefreshableMetadataResolver extends RefreshableMetadata
      * 
      * @return time the last successful refresh cycle occurred
      */
-    @Nullable public DateTime getLastSuccessfulRefresh();
+    @Nullable public Instant getLastSuccessfulRefresh();
 
     /**
      * Gets whether the last refresh cycle was successful.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/RefreshableMetadataResolver.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/RefreshableMetadataResolver.java
index c9ce871..30ed744 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/RefreshableMetadataResolver.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/metadata/resolver/RefreshableMetadataResolver.java
@@ -17,9 +17,9 @@
 
 package org.opensaml.saml.metadata.resolver;
 
-import javax.annotation.Nullable;
+import java.time.Instant;
 
-import org.joda.time.DateTime;
+import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
@@ -45,7 +45,7 @@ public interface RefreshableMetadataResolver extends MetadataResolver {
      * 
      * @return time the last refresh cycle occurred
      */
-    @Nullable DateTime getLastRefresh();
+    @Nullable Instant getLastRefresh();
 
     /**
      * Get the time that the currently available metadata was last updated. Note, this may be different than the time
@@ -54,7 +54,7 @@ public interface RefreshableMetadataResolver extends MetadataResolver {
      * 
      * @return time when the currently metadata was last updated, null if metadata has never successfully been read in
      */
-    @Nullable DateTime getLastUpdate();
+    @Nullable Instant getLastUpdate();
     
     //TODO For 4.0: promote getLastSuccessfulRefresh() and wasLastRefreshSuccess() 
     //     from ExtendedRefreshableMetadataResolver
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Assertion.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Assertion.java
index a62e60f..01c85af 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Assertion.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Assertion.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.saml1.core;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.annotation.Nonnull;
@@ -26,7 +27,6 @@ import javax.xml.namespace.QName;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.common.SignableSAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
@@ -122,14 +122,14 @@ public interface Assertion extends SignableSAMLObject, Evidentiary {
      * 
      * @return the Issue Instant (as a Date)
      */
-    @Nullable DateTime getIssueInstant();
+    @Nullable Instant getIssueInstant();
 
     /**
      * Set the IssueInstance (attribute).
      * 
      * @param issueInstant the issue instant value to set
      */
-    void setIssueInstant(@Nullable final DateTime issueInstant);
+    void setIssueInstant(@Nullable final Instant issueInstant);
 
     /**
      * Return the (singleton) Object, representing the <code> Conditions </code> sub element.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/AuthenticationStatement.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/AuthenticationStatement.java
index 5b1b7b0..72d7139 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/AuthenticationStatement.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/AuthenticationStatement.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml1.core;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
@@ -102,14 +102,14 @@ public interface AuthenticationStatement extends SAMLObject, SubjectStatement {
      * 
      * @return the authentication instant
      */
-    public DateTime getAuthenticationInstant();
+    public Instant getAuthenticationInstant();
 
     /**
      * Set the contents of the AuthenticationInstant attribute.
      *
      *  @param authenticationInstant the authentication instant
      */
-    public void setAuthenticationInstant(DateTime authenticationInstant);
+    public void setAuthenticationInstant(Instant authenticationInstant);
 
     /**
      * Get the {@link SubjectLocality}.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Conditions.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Conditions.java
index 84abdc6..a37944c 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Conditions.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/Conditions.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml1.core;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
@@ -55,28 +55,28 @@ public interface Conditions extends SAMLObject {
      * 
      * @return the "not before" condition 
      */
-    public DateTime getNotBefore();
+    public Instant getNotBefore();
 
     /**
      * Set the "not before" condition.
      * 
      * @param notBefore the "not before" condition 
      */
-    public void setNotBefore(DateTime notBefore);
+    public void setNotBefore(Instant notBefore);
 
     /**
      * Get the "not on or after" condition.
      * 
      * @return the "not on or after" condition 
      */
-    public DateTime getNotOnOrAfter();
+    public Instant getNotOnOrAfter();
 
     /**
      * Set the "not on or after" condition.
      * 
      * @param notOnOrAfter the "not on or after" condition 
      */
-    public void setNotOnOrAfter(DateTime notOnOrAfter);
+    public void setNotOnOrAfter(Instant notOnOrAfter);
     
     /**
      * Get the conditions.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/RequestAbstractType.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/RequestAbstractType.java
index aa0a5c6..f6cf399 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/RequestAbstractType.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/RequestAbstractType.java
@@ -21,9 +21,9 @@
 
 package org.opensaml.saml.saml1.core;
 
+import java.time.Instant;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.common.SignableSAMLObject;
 
@@ -63,14 +63,14 @@ public interface RequestAbstractType extends SignableSAMLObject {
      * 
      * @return the issue instant
      */
-    public DateTime getIssueInstant();
+    public Instant getIssueInstant();
 
     /**
      * Set the issue instant.
      * 
      * @param date what to set
      */
-    public void setIssueInstant(DateTime date);
+    public void setIssueInstant(Instant date);
 
     /**
      * Get the ID.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/ResponseAbstractType.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/ResponseAbstractType.java
index e4a33de..d2832c3 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/ResponseAbstractType.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/core/ResponseAbstractType.java
@@ -17,7 +17,8 @@
 
 package org.opensaml.saml.saml1.core;
 
-import org.joda.time.DateTime;
+import java.time.Instant;
+
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.common.SignableSAMLObject;
 
@@ -91,12 +92,12 @@ public interface ResponseAbstractType extends SignableSAMLObject {
      * 
      * @return the IssueInstant
      */
-    public DateTime getIssueInstant();
+    public Instant getIssueInstant();
 
     /** Set the Issue Instant (attribute).     * 
      * @param date what to set
      */
-    public void setIssueInstant(DateTime date);
+    public void setIssueInstant(Instant date);
 
     /**
      * Return the Recipient (attribute). .
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/profile/SAML1ActionSupport.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/profile/SAML1ActionSupport.java
index ad4507c..69879c8 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/profile/SAML1ActionSupport.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml1/profile/SAML1ActionSupport.java
@@ -17,12 +17,13 @@
 
 package org.opensaml.saml.saml1.profile;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.profile.action.AbstractProfileAction;
 import org.opensaml.saml.common.SAMLObjectBuilder;
@@ -60,7 +61,7 @@ public final class SAML1ActionSupport {
 
         final Assertion assertion = assertionBuilder.buildObject();
         assertion.setID(idGenerator.generateIdentifier());
-        assertion.setIssueInstant(new DateTime());
+        assertion.setIssueInstant(Instant.now());
         assertion.setIssuer(issuer);
         assertion.setVersion(SAMLVersion.VERSION_11);
         
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidator.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidator.java
index 40bfad0..b887135 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidator.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidator.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.saml2.assertion;
 
+import java.time.Instant;
 import java.util.Collection;
 import java.util.List;
 
@@ -29,8 +30,6 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.xml.SerializeSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.core.xml.util.XMLObjectSupport;
@@ -473,22 +472,22 @@ public class SAML20AssertionValidator {
             return ValidationResult.VALID;
         }
         
-        final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
+        final Instant now = Instant.now();
         final long clockSkew = getClockSkew(context);
 
-        final DateTime notBefore = conditions.getNotBefore();
+        final Instant notBefore = conditions.getNotBefore();
         log.debug("Evaluating Conditions NotBefore '{}' against 'skewed now' time '{}'",
-                notBefore, now.plus(clockSkew));
-        if (notBefore != null && notBefore.isAfter(now.plus(clockSkew))) {
+                notBefore, now.plusMillis(clockSkew));
+        if (notBefore != null && notBefore.isAfter(now.plusMillis(clockSkew))) {
             context.setValidationFailureMessage(String.format(
                     "Assertion '%s' with NotBefore condition of '%s' is not yet valid", assertion.getID(), notBefore));
             return ValidationResult.INVALID;
         }
 
-        final DateTime notOnOrAfter = conditions.getNotOnOrAfter();
+        final Instant notOnOrAfter = conditions.getNotOnOrAfter();
         log.debug("Evaluating Conditions NotOnOrAfter '{}' against 'skewed now' time '{}'",
-                notOnOrAfter, now.minus(clockSkew));
-        if (notOnOrAfter != null && notOnOrAfter.isBefore(now.minus(clockSkew))) {
+                notOnOrAfter, now.minusMillis(clockSkew));
+        if (notOnOrAfter != null && notOnOrAfter.isBefore(now.minusMillis(clockSkew))) {
             context.setValidationFailureMessage(String.format(
                     "Assertion '%s' with NotOnOrAfter condition of '%s' is no longer valid", assertion.getID(),
                     notOnOrAfter));
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/SAML2Support.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/SAML2Support.java
index 59417f0..7e78369 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/SAML2Support.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/SAML2Support.java
@@ -17,12 +17,12 @@
 
 package org.opensaml.saml.saml2.common;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 
 /**
@@ -69,9 +69,8 @@ public final class SAML2Support {
      * 
      * @return the earliest expiration time
      */
-    @Nullable public static DateTime getEarliestExpiration(@Nullable final XMLObject xmlObject) {
-        final DateTime now = new DateTime();
-        return getEarliestExpiration(xmlObject, null, now);
+    @Nullable public static Instant getEarliestExpiration(@Nullable final XMLObject xmlObject) {
+        return getEarliestExpiration(xmlObject, null, Instant.now());
     }
 
     /**
@@ -84,10 +83,10 @@ public final class SAML2Support {
      * @return the earliest expiration instant within a metadata tree. May be null if the input candiateTime 
      *          was null, otherwise will always be non-null.
      */
-    @Nullable public static DateTime getEarliestExpiration(@Nullable final XMLObject xmlObject, 
-            @Nullable final DateTime candidateTime, @Nonnull final DateTime now) {
+    @Nullable public static Instant getEarliestExpiration(@Nullable final XMLObject xmlObject, 
+            @Nullable final Instant candidateTime, @Nonnull final Instant now) {
         
-        DateTime earliestExpiration = candidateTime;
+        Instant earliestExpiration = candidateTime;
 
         // Test duration based times
         if (xmlObject instanceof CacheableSAMLObject) {
@@ -126,14 +125,14 @@ public final class SAML2Support {
      * @return the earliest effective expiration instant of the 2 targets. May be null if the input candiateTime 
      *          was null, otherwise will always be non-null.
      */
-    @Nullable public static DateTime getEarliestExpirationFromCacheable(
-            @Nonnull final CacheableSAMLObject cacheableObject, @Nullable final DateTime candidateTime,
-            @Nonnull final DateTime now) {
+    @Nullable public static Instant getEarliestExpirationFromCacheable(
+            @Nonnull final CacheableSAMLObject cacheableObject, @Nullable final Instant candidateTime,
+            @Nonnull final Instant now) {
         
-        DateTime earliestExpiration = candidateTime;
+        Instant earliestExpiration = candidateTime;
 
-        if (cacheableObject.getCacheDuration() != null && cacheableObject.getCacheDuration().longValue() > 0) {
-            final DateTime elementExpirationTime = now.plus(cacheableObject.getCacheDuration().longValue());
+        if (cacheableObject.getCacheDuration() != null && cacheableObject.getCacheDuration() > 0) {
+            final Instant elementExpirationTime = now.plusMillis(cacheableObject.getCacheDuration());
             if (earliestExpiration == null) {
                 earliestExpiration = elementExpirationTime;
             } else {
@@ -156,12 +155,12 @@ public final class SAML2Support {
      * @return the earliest effective expiration instant of the 2 targets. May be null if the input candiateTime 
      *          was null, otherwise will always be non-null.
      */
-    @Nullable public static DateTime getEarliestExpirationFromTimeBound(
-            @Nonnull final TimeBoundSAMLObject timeBoundObject, @Nullable final DateTime candidateTime) {
+    @Nullable public static Instant getEarliestExpirationFromTimeBound(
+            @Nonnull final TimeBoundSAMLObject timeBoundObject, @Nullable final Instant candidateTime) {
         
-        DateTime earliestExpiration = candidateTime;
+        Instant earliestExpiration = candidateTime;
         
-        final DateTime elementExpirationTime = timeBoundObject.getValidUntil();
+        final Instant elementExpirationTime = timeBoundObject.getValidUntil();
         if (earliestExpiration == null) {
             earliestExpiration = elementExpirationTime;
         } else {
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/TimeBoundSAMLObject.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/TimeBoundSAMLObject.java
index cf54b87..f6155bb 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/TimeBoundSAMLObject.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/common/TimeBoundSAMLObject.java
@@ -17,9 +17,10 @@
 
 package org.opensaml.saml.saml2.common;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
@@ -48,13 +49,13 @@ public interface TimeBoundSAMLObject extends SAMLObject{
      * 
      * @return the date until which this descriptor is valid
      */
-    public DateTime getValidUntil();
+    public Instant getValidUntil();
 
     /**
      * Sets the date until which this descriptor is valid.
      * 
      * @param validUntil the date until which this descriptor is valid
      */
-    public void setValidUntil(DateTime validUntil);
+    public void setValidUntil(Instant validUntil);
 
 }
\ No newline at end of file
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Assertion.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Assertion.java
index d28349b..a70e060 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Assertion.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Assertion.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml2.core;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.common.SignableSAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
@@ -73,14 +73,14 @@ public interface Assertion extends SignableSAMLObject, Evidentiary {
      * 
      * @return the issue instance of this assertion
      */
-    public DateTime getIssueInstant();
+    public Instant getIssueInstant();
 
     /**
      * Sets the issue instance of this assertion.
      * 
      * @param newIssueInstance the issue instance of this assertion
      */
-    public void setIssueInstant(DateTime newIssueInstance);
+    public void setIssueInstant(Instant newIssueInstance);
 
     /**
      * Sets the ID of this assertion.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/AuthnStatement.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/AuthnStatement.java
index 02e0c6f..8fac1ea 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/AuthnStatement.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/AuthnStatement.java
@@ -17,9 +17,10 @@
 
 package org.opensaml.saml.saml2.core;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
 /**
@@ -55,14 +56,14 @@ public interface AuthnStatement extends Statement {
      * 
      * @return the time when the authentication took place
      */
-    public DateTime getAuthnInstant();
+    public Instant getAuthnInstant();
 
     /**
      * Sets the time when the authentication took place.
      * 
      * @param newAuthnInstant the time when the authentication took place
      */
-    public void setAuthnInstant(DateTime newAuthnInstant);
+    public void setAuthnInstant(Instant newAuthnInstant);
 
     /**
      * Get the session index between the principal and the authenticating authority.
@@ -83,14 +84,14 @@ public interface AuthnStatement extends Statement {
      * 
      * @return the time when the session between the principal and the SAML authority ends
      */
-    public DateTime getSessionNotOnOrAfter();
+    public Instant getSessionNotOnOrAfter();
 
     /**
      * Set the time when the session between the principal and the SAML authority ends.
      * 
      * @param newSessionNotOnOrAfter the time when the session between the principal and the SAML authority ends
      */
-    public void setSessionNotOnOrAfter(DateTime newSessionNotOnOrAfter);
+    public void setSessionNotOnOrAfter(Instant newSessionNotOnOrAfter);
 
     /**
      * Get the DNS domain and IP address of the system where the principal was authenticated.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Conditions.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Conditions.java
index c869107..73cf19d 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Conditions.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/Conditions.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml2.core;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
@@ -55,28 +55,28 @@ public interface Conditions extends SAMLObject {
      * 
      * @return the date/time before which the assertion is invalid
      */
-    public DateTime getNotBefore();
+    public Instant getNotBefore();
 
     /**
      * Sets the date/time before which the assertion is invalid.
      * 
      * @param newNotBefore the date/time before which the assertion is invalid
      */
-    public void setNotBefore(DateTime newNotBefore);
+    public void setNotBefore(Instant newNotBefore);
 
     /**
      * Gets the date/time on, or after, which the assertion is invalid.
      * 
      * @return the date/time on, or after, which the assertion is invalid
      */
-    public DateTime getNotOnOrAfter();
+    public Instant getNotOnOrAfter();
 
     /**
      * Sets the date/time on, or after, which the assertion is invalid.
      * 
      * @param newNotOnOrAfter the date/time on, or after, which the assertion is invalid
      */
-    public void setNotOnOrAfter(DateTime newNotOnOrAfter);
+    public void setNotOnOrAfter(Instant newNotOnOrAfter);
 
     /**
      * Gets all the conditions on the assertion.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/LogoutRequest.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/LogoutRequest.java
index 0f56895..7645fa6 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/LogoutRequest.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/LogoutRequest.java
@@ -20,11 +20,11 @@
  */
 package org.opensaml.saml.saml2.core;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.xml.SAMLConstants;
 
 /**
@@ -83,14 +83,14 @@ public interface LogoutRequest extends RequestAbstractType {
      * 
      * @return the NotOnOrAfter value of the request
      */
-    public DateTime getNotOnOrAfter();
+    public Instant getNotOnOrAfter();
 
     /**
      * Set the NotOnOrAfter attrib value of the request.
      * 
      * @param newNotOnOrAfter the new NotOnOrAfter value of the request
      */
-    public void setNotOnOrAfter(DateTime newNotOnOrAfter);
+    public void setNotOnOrAfter(Instant newNotOnOrAfter);
     
     /**
      * Gets the base identifier of the principal for this request.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/RequestAbstractType.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/RequestAbstractType.java
index fcd2648..41ce1c7 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/RequestAbstractType.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/RequestAbstractType.java
@@ -17,9 +17,10 @@
 
 package org.opensaml.saml.saml2.core;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.common.SignableSAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
@@ -107,14 +108,14 @@ public interface RequestAbstractType extends SignableSAMLObject {
      * @return the date/time the request was issued
      */
 
-    public DateTime getIssueInstant();
+    public Instant getIssueInstant();
 
     /**
      * Sets the date/time the request was issued.
      * 
      * @param newIssueInstant the date/time the request was issued
      */
-    public void setIssueInstant(DateTime newIssueInstant);
+    public void setIssueInstant(Instant newIssueInstant);
 
     /**
      * Gets the URI of the destination of the request.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/StatusResponseType.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/StatusResponseType.java
index 6fc5d6e..d9ce0fc 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/StatusResponseType.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/StatusResponseType.java
@@ -21,9 +21,10 @@
 
 package org.opensaml.saml.saml2.core;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.common.SignableSAMLObject;
 import org.opensaml.saml.common.xml.SAMLConstants;
@@ -128,14 +129,14 @@ public interface StatusResponseType extends SignableSAMLObject {
      * 
      * @return the date/time the response was issued
      */
-    public DateTime getIssueInstant();
+    public Instant getIssueInstant();
 
     /**
      * Sets the date/time the response was issued.
      * 
      * @param newIssueInstant the date/time the response was issued
      */
-    public void setIssueInstant(DateTime newIssueInstant);
+    public void setIssueInstant(Instant newIssueInstant);
 
     /**
      * Gets the URI of the destination of the response.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/SubjectConfirmationData.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/SubjectConfirmationData.java
index 22dcaee..828cb42 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/SubjectConfirmationData.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/core/SubjectConfirmationData.java
@@ -17,9 +17,10 @@
 
 package org.opensaml.saml.saml2.core;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.AttributeExtensibleXMLObject;
 import org.opensaml.core.xml.ElementExtensibleXMLObject;
 import org.opensaml.saml.common.SAMLObject;
@@ -64,28 +65,28 @@ public interface SubjectConfirmationData extends SAMLObject, ElementExtensibleXM
      * 
      * @return the time before which this subject is not valid
      */
-    public DateTime getNotBefore();
+    public Instant getNotBefore();
 
     /**
      * Sets the time before which this subject is not valid.
      * 
      * @param newNotBefore the time before which this subject is not valid
      */
-    public void setNotBefore(DateTime newNotBefore);
+    public void setNotBefore(Instant newNotBefore);
 
     /**
      * Gets the time at, or after, which this subject is not valid.
      * 
      * @return the time at, or after, which this subject is not valid
      */
-    public DateTime getNotOnOrAfter();
+    public Instant getNotOnOrAfter();
 
     /**
      * Sets the time at, or after, which this subject is not valid.
      * 
      * @param newNotOnOrAfter the time at, or after, which this subject is not valid
      */
-    public void setNotOnOrAfter(DateTime newNotOnOrAfter);
+    public void setNotOnOrAfter(Instant newNotOnOrAfter);
 
     /**
      * Gets the recipient of this subject.
diff --git a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/profile/SAML2ActionSupport.java b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/profile/SAML2ActionSupport.java
index c531d59..58ebd29 100644
--- a/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/profile/SAML2ActionSupport.java
+++ b/opensaml-saml-api/src/main/java/org/opensaml/saml/saml2/profile/SAML2ActionSupport.java
@@ -17,12 +17,13 @@
 
 package org.opensaml.saml.saml2.profile;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.profile.action.AbstractProfileAction;
 import org.opensaml.saml.common.SAMLObjectBuilder;
@@ -62,7 +63,7 @@ public final class SAML2ActionSupport {
 
         final Assertion assertion = assertionBuilder.buildObject();
         assertion.setID(idGenerator.generateIdentifier());
-        assertion.setIssueInstant(new DateTime());
+        assertion.setIssueInstant(Instant.now());
         assertion.setVersion(SAMLVersion.VERSION_20);
 
         if (issuer != null) {
diff --git a/opensaml-saml-api/src/test/java/org/opensaml/saml/saml1/profile/SAML1ActionTestingSupport.java b/opensaml-saml-api/src/test/java/org/opensaml/saml/saml1/profile/SAML1ActionTestingSupport.java
index 2cf7099..63529a3 100644
--- a/opensaml-saml-api/src/test/java/org/opensaml/saml/saml1/profile/SAML1ActionTestingSupport.java
+++ b/opensaml-saml-api/src/test/java/org/opensaml/saml/saml1/profile/SAML1ActionTestingSupport.java
@@ -17,10 +17,11 @@
 
 package org.opensaml.saml.saml1.profile;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.profile.action.ActionTestingSupport;
 import org.opensaml.saml.common.SAMLObjectBuilder;
@@ -63,7 +64,7 @@ public class SAML1ActionTestingSupport {
 
         final Response response = responseBuilder.buildObject();
         response.setID(ActionTestingSupport.OUTBOUND_MSG_ID);
-        response.setIssueInstant(new DateTime(0));
+        response.setIssueInstant(Instant.ofEpochMilli(0));
         response.setVersion(SAMLVersion.VERSION_11);
 
         return response;
@@ -82,7 +83,7 @@ public class SAML1ActionTestingSupport {
 
         final Assertion assertion = assertionBuilder.buildObject();
         assertion.setID(ASSERTION_ID);
-        assertion.setIssueInstant(new DateTime(0));
+        assertion.setIssueInstant(Instant.ofEpochMilli(0));
         assertion.setVersion(SAMLVersion.VERSION_11);
 
         return assertion;
@@ -100,7 +101,7 @@ public class SAML1ActionTestingSupport {
                         AuthenticationStatement.DEFAULT_ELEMENT_NAME);
 
         final AuthenticationStatement statement = statementBuilder.buildObject();
-        statement.setAuthenticationInstant(new DateTime(0));
+        statement.setAuthenticationInstant(Instant.ofEpochMilli(0));
         statement.setAuthenticationMethod(AuthenticationStatement.PASSWORD_AUTHN_METHOD);
 
         return statement;
@@ -170,7 +171,7 @@ public class SAML1ActionTestingSupport {
                         Request.DEFAULT_ELEMENT_NAME);
         final Request request = requestBuilder.buildObject();
         request.setID(REQUEST_ID);
-        request.setIssueInstant(new DateTime(0));
+        request.setIssueInstant(Instant.ofEpochMilli(0));
         request.setQuery(query);
         request.setVersion(SAMLVersion.VERSION_11);
 
@@ -194,7 +195,7 @@ public class SAML1ActionTestingSupport {
                         Request.DEFAULT_ELEMENT_NAME);
         final Request request = requestBuilder.buildObject();
         request.setID(REQUEST_ID);
-        request.setIssueInstant(new DateTime(0));
+        request.setIssueInstant(Instant.ofEpochMilli(0));
         request.setVersion(SAMLVersion.VERSION_11);
         
         if (artifacts != null) {
diff --git a/opensaml-saml-api/src/test/java/org/opensaml/saml/saml2/profile/SAML2ActionTestingSupport.java b/opensaml-saml-api/src/test/java/org/opensaml/saml/saml2/profile/SAML2ActionTestingSupport.java
index 578bbca..a82027d 100644
--- a/opensaml-saml-api/src/test/java/org/opensaml/saml/saml2/profile/SAML2ActionTestingSupport.java
+++ b/opensaml-saml-api/src/test/java/org/opensaml/saml/saml2/profile/SAML2ActionTestingSupport.java
@@ -17,12 +17,13 @@
 
 package org.opensaml.saml.saml2.profile;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.profile.action.ActionTestingSupport;
 import org.opensaml.saml.common.SAMLObjectBuilder;
@@ -70,7 +71,7 @@ public class SAML2ActionTestingSupport {
 
         final Response response = responseBuilder.buildObject();
         response.setID(ActionTestingSupport.OUTBOUND_MSG_ID);
-        response.setIssueInstant(new DateTime(0));
+        response.setIssueInstant(Instant.ofEpochMilli(0));
         response.setVersion(SAMLVersion.VERSION_20);
 
         return response;
@@ -89,7 +90,7 @@ public class SAML2ActionTestingSupport {
 
         final ArtifactResponse response = responseBuilder.buildObject();
         response.setID(ActionTestingSupport.OUTBOUND_MSG_ID);
-        response.setIssueInstant(new DateTime(0));
+        response.setIssueInstant(Instant.ofEpochMilli(0));
         response.setVersion(SAMLVersion.VERSION_20);
 
         return response;
@@ -117,7 +118,7 @@ public class SAML2ActionTestingSupport {
 
         final LogoutRequest req = reqBuilder.buildObject();
         req.setID(REQUEST_ID);
-        req.setIssueInstant(new DateTime(0));
+        req.setIssueInstant(Instant.ofEpochMilli(0));
         req.setIssuer(issuer);
         req.setVersion(SAMLVersion.VERSION_20);
 
@@ -141,7 +142,7 @@ public class SAML2ActionTestingSupport {
 
         final LogoutResponse response = responseBuilder.buildObject();
         response.setID(ActionTestingSupport.OUTBOUND_MSG_ID);
-        response.setIssueInstant(new DateTime(0));
+        response.setIssueInstant(Instant.ofEpochMilli(0));
         response.setVersion(SAMLVersion.VERSION_20);
 
         return response;
@@ -160,7 +161,7 @@ public class SAML2ActionTestingSupport {
 
         final Assertion assertion = assertionBuilder.buildObject();
         assertion.setID(ASSERTION_ID);
-        assertion.setIssueInstant(new DateTime(0));
+        assertion.setIssueInstant(Instant.ofEpochMilli(0));
         assertion.setVersion(SAMLVersion.VERSION_20);
 
         return assertion;
@@ -177,7 +178,7 @@ public class SAML2ActionTestingSupport {
                         AuthnStatement.DEFAULT_ELEMENT_NAME);
 
         final AuthnStatement statement = statementBuilder.buildObject();
-        statement.setAuthnInstant(new DateTime(0));
+        statement.setAuthnInstant(Instant.ofEpochMilli(0));
 
         return statement;
     }
@@ -272,7 +273,7 @@ public class SAML2ActionTestingSupport {
 
         final AttributeQuery query = queryBuilder.buildObject();
         query.setID(REQUEST_ID);
-        query.setIssueInstant(new DateTime(0));
+        query.setIssueInstant(Instant.ofEpochMilli(0));
         query.setIssuer(issuer);
         query.setVersion(SAMLVersion.VERSION_20);
 
@@ -302,7 +303,7 @@ public class SAML2ActionTestingSupport {
 
         final AuthnRequest request = requestBuilder.buildObject();
         request.setID(REQUEST_ID);
-        request.setIssueInstant(new DateTime(0));
+        request.setIssueInstant(Instant.ofEpochMilli(0));
         request.setIssuer(issuer);
         request.setVersion(SAMLVersion.VERSION_20);
 
@@ -322,7 +323,7 @@ public class SAML2ActionTestingSupport {
                         ArtifactResolve.DEFAULT_ELEMENT_NAME);
         final ArtifactResolve request = requestBuilder.buildObject();
         request.setID(REQUEST_ID);
-        request.setIssueInstant(new DateTime(0));
+        request.setIssueInstant(Instant.ofEpochMilli(0));
         request.setVersion(SAMLVersion.VERSION_11);
         
         if (artifact != null) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/artifact/impl/BasicSAMLArtifactMap.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/artifact/impl/BasicSAMLArtifactMap.java
index 413f0f8..a79ba06 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/artifact/impl/BasicSAMLArtifactMap.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/artifact/impl/BasicSAMLArtifactMap.java
@@ -18,6 +18,7 @@
 package org.opensaml.saml.common.binding.artifact.impl;
 
 import java.io.IOException;
+import java.time.Instant;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Timer;
@@ -37,7 +38,6 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.TimerSupport;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.binding.artifact.ExpiringSAMLArtifactMapEntry;
 import org.opensaml.saml.common.binding.artifact.SAMLArtifactMap;
@@ -180,7 +180,7 @@ public class BasicSAMLArtifactMap extends AbstractInitializableComponent impleme
 
         if (log.isDebugEnabled()) {
             log.debug("Storing new artifact entry '{}' for relying party '{}', expiring at '{}'", new Object[] {
-                    artifact, relyingPartyId, new DateTime(artifactEntry.getExpiration()),});
+                    artifact, relyingPartyId, Instant.ofEpochMilli(artifactEntry.getExpiration()),});
         }
 
         artifactStore.put(artifact, artifactEntry);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandler.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandler.java
index f6a47aa..c7dced3 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandler.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandler.java
@@ -17,6 +17,8 @@
 
 package org.opensaml.saml.common.binding.security.impl;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 
 import net.shibboleth.utilities.java.support.annotation.Duration;
@@ -24,8 +26,6 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NonNegative;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.handler.AbstractMessageHandler;
 import org.opensaml.messaging.handler.MessageHandlerException;
@@ -135,10 +135,10 @@ public class MessageLifetimeSecurityHandler extends AbstractMessageHandler {
             }
         }
 
-        final DateTime issueInstant = msgInfoContext.getMessageIssueInstant();
-        final DateTime now = new DateTime(DateTimeZone.UTC);
-        final DateTime latestValid = now.plus(getClockSkew());
-        final DateTime expiration = issueInstant.plus(getClockSkew() + getMessageLifetime());
+        final Instant issueInstant = msgInfoContext.getMessageIssueInstant();
+        final Instant now = Instant.now();
+        final Instant latestValid = now.plusMillis(getClockSkew());
+        final Instant expiration = issueInstant.plusMillis(getClockSkew() + getMessageLifetime());
 
         // Check message wasn't issued in the future
         if (issueInstant.isAfter(latestValid)) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageReplaySecurityHandler.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageReplaySecurityHandler.java
index 8cdbd9b..eb94faa 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageReplaySecurityHandler.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/binding/security/impl/MessageReplaySecurityHandler.java
@@ -17,6 +17,8 @@
 
 package org.opensaml.saml.common.binding.security.impl;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 
 import net.shibboleth.utilities.java.support.annotation.Duration;
@@ -27,7 +29,6 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
-import org.joda.time.DateTime;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.handler.AbstractMessageHandler;
 import org.opensaml.messaging.handler.MessageHandlerException;
@@ -144,15 +145,15 @@ public class MessageReplaySecurityHandler extends AbstractMessageHandler {
             }
         }
 
-        DateTime issueInstant = msgInfoContext.getMessageIssueInstant();
+        Instant issueInstant = msgInfoContext.getMessageIssueInstant();
         if (issueInstant == null) {
-            issueInstant = new DateTime();
+            issueInstant = Instant.now();
         }
         
         log.debug("{} Evaluating message replay for message ID '{}', issue instant '{}', entityID '{}'", 
                 getLogPrefix(), messageId, issueInstant, entityID);
         
-        if (!getReplayCache().check(getClass().getName(), messageId, issueInstant.getMillis() + expires)) {
+        if (!getReplayCache().check(getClass().getName(), messageId, issueInstant.toEpochMilli() + expires)) {
             log.warn("{} Replay detected of message '{}' from issuer '{}'", getLogPrefix(), messageId, entityID);
             throw new MessageHandlerException("Rejecting replayed message ID '" + messageId + "' from issuer "
                     + entityID);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertions.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertions.java
index ac5640c..5f9160a 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertions.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertions.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.common.profile.impl;
 
+import java.time.Instant;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -27,7 +28,6 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NonNegative;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
-import org.joda.time.DateTime;
 import org.opensaml.messaging.context.navigate.MessageLookup;
 import org.opensaml.profile.action.AbstractConditionalProfileAction;
 import org.opensaml.profile.action.ActionSupport;
@@ -151,7 +151,7 @@ public class AddNotOnOrAfterConditionToAssertions extends AbstractConditionalPro
             for (final org.opensaml.saml.saml1.core.Assertion assertion :
                     ((org.opensaml.saml.saml1.core.Response) response).getAssertions()) {
 
-                final DateTime expiration = new DateTime(assertion.getIssueInstant()).plus(
+                final Instant expiration = assertion.getIssueInstant().plusMillis(
                         lifetime != null ? lifetime : defaultAssertionLifetime);
                 log.debug("{} Added NotOnOrAfter condition, indicating an expiration of {}, to Assertion {}",
                         new Object[] {getLogPrefix(), expiration, assertion.getID()});
@@ -161,7 +161,7 @@ public class AddNotOnOrAfterConditionToAssertions extends AbstractConditionalPro
             for (final org.opensaml.saml.saml2.core.Assertion assertion :
                     ((org.opensaml.saml.saml2.core.Response) response).getAssertions()) {
 
-                final DateTime expiration = new DateTime(assertion.getIssueInstant()).plus(
+                final Instant expiration = assertion.getIssueInstant().plusMillis(
                         lifetime != null ? lifetime : defaultAssertionLifetime);
                 log.debug("{} Added NotOnOrAfter condition, indicating an expiration of {}, to Assertion {}",
                         new Object[] {getLogPrefix(), expiration, assertion.getID()});
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateImpl.java
index 908e806..a2b4577 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateImpl.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.ext.saml2delrestrict.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.AbstractSAMLObject;
 import org.opensaml.saml.ext.saml2delrestrict.Delegate;
@@ -44,7 +44,7 @@ public class DelegateImpl extends AbstractSAMLObject implements Delegate {
     private EncryptedID encryptedID;
     
     /** DelegationInstant attribute. */
-    private DateTime delegationInstant;
+    private Instant delegationInstant;
     
     /** ConfirmationMethod attribute. */
     private String confirmationMethod;
@@ -71,7 +71,7 @@ public class DelegateImpl extends AbstractSAMLObject implements Delegate {
     }
 
     /** {@inheritDoc} */
-    public DateTime getDelegationInstant() {
+    public Instant getDelegationInstant() {
         return delegationInstant;
     }
 
@@ -96,7 +96,7 @@ public class DelegateImpl extends AbstractSAMLObject implements Delegate {
     }
 
     /** {@inheritDoc} */
-    public void setDelegationInstant(final DateTime newInstant) {
+    public void setDelegationInstant(final Instant newInstant) {
         delegationInstant = prepareForAssignment(delegationInstant, newInstant);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateMarshaller.java
index 7560e07..f1cb891 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateMarshaller.java
@@ -37,7 +37,7 @@ public class DelegateMarshaller extends AbstractSAMLObjectMarshaller {
         
         if (delegate.getDelegationInstant() != null) {
             final String delInstant =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(delegate.getDelegationInstant());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(delegate.getDelegationInstant());
             domElement.setAttributeNS(null, Delegate.DELEGATION_INSTANT_ATTRIB_NAME, delInstant);
         }
         if (!Strings.isNullOrEmpty(delegate.getConfirmationMethod())) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateUnmarshaller.java
index cca496a..748c99f 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.ext.saml2delrestrict.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -42,7 +42,7 @@ public class DelegateUnmarshaller extends AbstractSAMLObjectUnmarshaller {
             if (Delegate.CONFIRMATION_METHOD_ATTRIB_NAME.equals(attrName)) {
                 delegate.setConfirmationMethod(attribute.getValue());
             } else if (Delegate.DELEGATION_INSTANT_ATTRIB_NAME.equals(attrName)) {
-                delegate.setDelegationInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                delegate.setDelegationInstant(Instant.parse(attribute.getValue()));
             } else {
                 super.processAttribute(samlObject, attribute);
             }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationImpl.java
index a0bb2ed..1d33630 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationImpl.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
+import java.time.Instant;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.AbstractSAMLObject;
 import org.opensaml.saml.ext.saml2mdrpi.Publication;
@@ -34,7 +34,7 @@ public class PublicationImpl extends AbstractSAMLObject implements Publication {
     private String publisher;
 
     /** The creation instant. */
-    private DateTime creationInstant;
+    private Instant creationInstant;
 
     /** The publicationId. */
     private String publicationId;
@@ -62,12 +62,12 @@ public class PublicationImpl extends AbstractSAMLObject implements Publication {
     }
 
     /** {@inheritDoc} */
-    public DateTime getCreationInstant() {
+    public Instant getCreationInstant() {
         return creationInstant;
     }
 
     /** {@inheritDoc} */
-    public void setCreationInstant(final DateTime dateTime) {
+    public void setCreationInstant(final Instant dateTime) {
         creationInstant = prepareForAssignment(creationInstant, dateTime);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoImpl.java
index 4ffc37e..4f0d629 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoImpl.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 import org.opensaml.core.xml.util.XMLObjectChildrenList;
@@ -40,7 +40,7 @@ public class PublicationInfoImpl extends AbstractSAMLObject implements Publicati
     private String publisher;
 
     /** The creation instant. */
-    private DateTime creationInstant;
+    private Instant creationInstant;
 
     /** The publicationId. */
     private String publicationId;
@@ -72,13 +72,13 @@ public class PublicationInfoImpl extends AbstractSAMLObject implements Publicati
 
     /** {@inheritDoc} */
     @Override
-    public DateTime getCreationInstant() {
+    public Instant getCreationInstant() {
         return creationInstant;
     }
 
     /** {@inheritDoc} */
     @Override
-    public void setCreationInstant(final DateTime dateTime) {
+    public void setCreationInstant(final Instant dateTime) {
         creationInstant = prepareForAssignment(creationInstant, dateTime);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoMarshaller.java
index 399a164..a36bb2f 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoMarshaller.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.format.ISODateTimeFormat;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectMarshaller;
+import org.opensaml.saml.config.SAMLConfigurationSupport;
 import org.opensaml.saml.ext.saml2mdrpi.PublicationInfo;
 import org.w3c.dom.Element;
 
@@ -46,7 +46,8 @@ public class PublicationInfoMarshaller extends AbstractSAMLObjectMarshaller {
 
 
         if (info.getCreationInstant() != null) {
-            final String creationInstant = ISODateTimeFormat.dateTime().print(info.getCreationInstant());
+            final String creationInstant =
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(info.getCreationInstant());
             domElement.setAttributeNS(null, PublicationInfo.CREATION_INSTANT_ATTRIB_NAME, creationInstant);
         }
     }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoUnmarshaller.java
index 3a67b59..584ef6d 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -51,7 +51,7 @@ public class PublicationInfoUnmarshaller extends AbstractSAMLObjectUnmarshaller
             if (PublicationInfo.PUBLISHER_ATTRIB_NAME.equals(attribute.getName())) {
                 info.setPublisher(attribute.getValue());
             } else if (PublicationInfo.CREATION_INSTANT_ATTRIB_NAME.equals(attribute.getName())) {
-                info.setCreationInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                info.setCreationInstant(Instant.parse(attribute.getValue()));
             } else if (PublicationInfo.PUBLICATION_ID_ATTRIB_NAME.equals(attribute.getName())) {
                 info.setPublicationId(attribute.getValue());
             } else {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationMarshaller.java
index d807aeb..a95df2c 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationMarshaller.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.format.ISODateTimeFormat;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectMarshaller;
+import org.opensaml.saml.config.SAMLConfigurationSupport;
 import org.opensaml.saml.ext.saml2mdrpi.Publication;
 import org.w3c.dom.Element;
 
@@ -46,8 +46,10 @@ public class PublicationMarshaller extends AbstractSAMLObjectMarshaller {
 
 
         if (info.getCreationInstant() != null) {
-            final String creationInstant = ISODateTimeFormat.dateTime().print(info.getCreationInstant());
+            final String creationInstant =
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(info.getCreationInstant());
             domElement.setAttributeNS(null, Publication.CREATION_INSTANT_ATTRIB_NAME, creationInstant);
         }
     }
-}
+    
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationUnmarshaller.java
index f31a956..b260de4 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -38,7 +38,7 @@ public class PublicationUnmarshaller extends AbstractSAMLObjectUnmarshaller {
             if (Publication.PUBLISHER_ATTRIB_NAME.equals(attribute.getName())) {
                 info.setPublisher(attribute.getValue());
             } else if (Publication.CREATION_INSTANT_ATTRIB_NAME.equals(attribute.getName())) {
-                info.setCreationInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                info.setCreationInstant(Instant.parse(attribute.getValue()));
             } else if (Publication.PUBLICATION_ID_ATTRIB_NAME.equals(attribute.getName())) {
                 info.setPublicationId(attribute.getValue());
             } else {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoImpl.java
index 0206cdf..0f87b0d 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoImpl.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 import org.opensaml.core.xml.util.XMLObjectChildrenList;
@@ -40,7 +40,7 @@ public class RegistrationInfoImpl extends AbstractSAMLObject implements Registra
     private String registrationAuthority;
 
     /** The registration instant. */
-    private DateTime registrationInstant;
+    private Instant registrationInstant;
 
     /**
      * Constructor.
@@ -69,13 +69,13 @@ public class RegistrationInfoImpl extends AbstractSAMLObject implements Registra
 
     /** {@inheritDoc} */
     @Override
-    public DateTime getRegistrationInstant() {
+    public Instant getRegistrationInstant() {
         return registrationInstant;
     }
 
     /** {@inheritDoc} */
     @Override
-    public void setRegistrationInstant(final DateTime dateTime) {
+    public void setRegistrationInstant(final Instant dateTime) {
         registrationInstant = prepareForAssignment(registrationInstant, dateTime);
     }
 
@@ -92,4 +92,5 @@ public class RegistrationInfoImpl extends AbstractSAMLObject implements Registra
         children.addAll(registrationPolicies);
         return children;
     }
-}
+    
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoMarshaller.java
index 5def435..5aaf76b 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoMarshaller.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.format.ISODateTimeFormat;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectMarshaller;
+import org.opensaml.saml.config.SAMLConfigurationSupport;
 import org.opensaml.saml.ext.saml2mdrpi.RegistrationInfo;
 import org.w3c.dom.Element;
 
@@ -40,7 +40,8 @@ public class RegistrationInfoMarshaller extends AbstractSAMLObjectMarshaller {
         }
 
         if (info.getRegistrationInstant() != null) {
-            final String registrationInstant = ISODateTimeFormat.dateTime().print(info.getRegistrationInstant());
+            final String registrationInstant =
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(info.getRegistrationInstant());
             domElement.setAttributeNS(null, RegistrationInfo.REGISTRATION_INSTANT_ATTRIB_NAME, registrationInstant);
         }
     }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoUnmarshaller.java
index 88cc6fc..7d496a5 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -51,7 +51,7 @@ public class RegistrationInfoUnmarshaller extends AbstractSAMLObjectUnmarshaller
             if (RegistrationInfo.REGISTRATION_AUTHORITY_ATTRIB_NAME.equals(attribute.getName())) {
                 info.setRegistrationAuthority(attribute.getValue());
             } else if (RegistrationInfo.REGISTRATION_INSTANT_ATTRIB_NAME.equals(attribute.getName())) {
-                info.setRegistrationInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                info.setRegistrationInstant(Instant.parse(attribute.getValue()));
             } else {
                 super.processAttribute(samlObject, attribute);
             }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilFilter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilFilter.java
index a267c7c..5a71a85 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilFilter.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilFilter.java
@@ -17,14 +17,14 @@
 
 package org.opensaml.saml.metadata.resolver.filter.impl;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.annotation.Duration;
 import net.shibboleth.utilities.java.support.xml.DOMTypeSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.metadata.resolver.filter.FilterException;
 import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;
@@ -90,15 +90,15 @@ public class RequiredValidUntilFilter implements MetadataFilter {
             return null;
         }
         
-        final DateTime validUntil = getValidUntil(metadata);
+        final Instant validUntil = getValidUntil(metadata);
 
         if (validUntil == null) {
             throw new FilterException("Metadata did not include a validUntil attribute");
         }
 
-        final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
+        final Instant now = Instant.now();
         if (maxValidityInterval > 0 && validUntil.isAfter(now)) {
-            final long validityInterval = validUntil.getMillis() - now.getMillis();
+            final long validityInterval = validUntil.toEpochMilli() - now.toEpochMilli();
             if (validityInterval > maxValidityInterval) {
                 throw new FilterException(String.format("Metadata's validity interval %s is larger than is allowed %s", 
                         DOMTypeSupport.longToDuration(validityInterval),
@@ -119,7 +119,7 @@ public class RequiredValidUntilFilter implements MetadataFilter {
      * @throws FilterException thrown if the given XML object is not an {@link EntitiesDescriptor} or
      *             {@link EntityDescriptor}
      */
-    @Nullable protected DateTime getValidUntil(@Nonnull final XMLObject metadata) throws FilterException {
+    @Nullable protected Instant getValidUntil(@Nonnull final XMLObject metadata) throws FilterException {
         if (metadata instanceof EntitiesDescriptor) {
             return ((EntitiesDescriptor) metadata).getValidUntil();
         } else if (metadata instanceof EntityDescriptor) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractBatchMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractBatchMetadataResolver.java
index 1d7486d..c42fcb9 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractBatchMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractBatchMetadataResolver.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.metadata.resolver.impl;
 
+import java.time.Instant;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -25,7 +26,6 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.metadata.IterableMetadataSource;
@@ -154,7 +154,7 @@ public abstract class AbstractBatchMetadataResolver extends AbstractMetadataReso
     }
 
     /** {@inheritDoc} */
-    @Nullable public DateTime getRootValidUntil() {
+    @Nullable public Instant getRootValidUntil() {
         final XMLObject cached = getBackingStore().getCachedOriginalMetadata();
         if (cached != null && cached instanceof TimeBoundSAMLObject) {
             return ((TimeBoundSAMLObject)cached).getValidUntil();
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java
index 53bd0c5..54788aa 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractDynamicMetadataResolver.java
@@ -19,6 +19,7 @@ package org.opensaml.saml.metadata.resolver.impl;
 
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -38,8 +39,6 @@ import java.util.function.Predicate;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.core.metrics.MetricsSupport;
 import org.opensaml.core.xml.XMLObject;
@@ -870,7 +869,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
 
                 if (!descriptors.isEmpty()) {
                     mgmtData.setRefreshTriggerTime(computeRefreshTriggerTime(mgmtData.getExpirationTime(), 
-                            new DateTime(ISOChronology.getInstanceUTC())));
+                            Instant.now()));
                     log.debug("{} Had existing data, recalculated refresh trigger time as: {}", 
                             getLogPrefix(), mgmtData.getRefreshTriggerTime());
                 }
@@ -1168,7 +1167,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
         final DynamicEntityBackingStore dynamicBackingStore = (DynamicEntityBackingStore) backingStore;
         final EntityManagementData mgmtData = dynamicBackingStore.getManagementData(entityID);
         
-        final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
+        final Instant now = Instant.now();
         log.debug("{} For metadata expiration and refresh computation, 'now' is : {}", getLogPrefix(), now);
         
         mgmtData.setLastUpdateTime(now);
@@ -1190,14 +1189,14 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
      * @param nextRefresh  the next refresh trigger time for the entity descriptor
      */
     private void logMetadataExpiration(@Nonnull final EntityDescriptor descriptor,
-            @Nonnull final DateTime now, @Nonnull final DateTime nextRefresh) {
+            @Nonnull final Instant now, @Nonnull final Instant nextRefresh) {
         if (!isValid(descriptor)) {
             log.warn("{} Metadata with ID '{}' currently live is expired or otherwise invalid",
                     getLogPrefix(), descriptor.getEntityID());
         } else {
             if (isRequireValidMetadata() && descriptor.getValidUntil() != null) {
                 if (getExpirationWarningThreshold() > 0 
-                        && descriptor.getValidUntil().isBefore(now.plus(getExpirationWarningThreshold()))) {
+                        && descriptor.getValidUntil().isBefore(now.plusMillis(getExpirationWarningThreshold()))) {
                     log.warn("{} Metadata with ID '{}' currently live will expire "
                             + "within the configured threshhold at '{}'",
                             getLogPrefix(), descriptor.getEntityID(), descriptor.getValidUntil());
@@ -1217,13 +1216,13 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
      * @param now the current date time instant
      * @return the effective expiration time for the metadata
      */
-    @Nonnull protected DateTime computeExpirationTime(@Nonnull final EntityDescriptor entityDescriptor,
-            @Nonnull final DateTime now) {
+    @Nonnull protected Instant computeExpirationTime(@Nonnull final EntityDescriptor entityDescriptor,
+            @Nonnull final Instant now) {
         
-        final DateTime lowerBound = now.toDateTime(ISOChronology.getInstanceUTC()).plus(getMinCacheDuration());
+        final Instant lowerBound = now.plusMillis(getMinCacheDuration());
         
-        DateTime expiration = SAML2Support.getEarliestExpiration(entityDescriptor, 
-                now.plus(getMaxCacheDuration()), now);
+        Instant expiration = SAML2Support.getEarliestExpiration(entityDescriptor, 
+                now.plusMillis(getMaxCacheDuration()), now);
         if (expiration.isBefore(lowerBound)) {
             expiration = lowerBound;
         }
@@ -1239,15 +1238,14 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
      * 
      * @return the time after which refresh attempt(s) should be made
      */
-    @Nonnull protected DateTime computeRefreshTriggerTime(@Nullable final DateTime expirationTime,
-            @Nonnull final DateTime nowDateTime) {
+    @Nonnull protected Instant computeRefreshTriggerTime(@Nullable final Instant expirationTime,
+            @Nonnull final Instant nowDateTime) {
         
-        final DateTime nowDateTimeUTC = nowDateTime.toDateTime(ISOChronology.getInstanceUTC());
-        final long now = nowDateTimeUTC.getMillis();
+        final long now = nowDateTime.toEpochMilli();
 
         long expireInstant = 0;
         if (expirationTime != null) {
-            expireInstant = expirationTime.toDateTime(ISOChronology.getInstanceUTC()).getMillis();
+            expireInstant = expirationTime.toEpochMilli();
         }
         long refreshDelay = (long) ((expireInstant - now) * getRefreshDelayFactor());
 
@@ -1257,7 +1255,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
             refreshDelay = getMinCacheDuration();
         }
 
-        return nowDateTimeUTC.plus(refreshDelay);
+        return nowDateTime.plusMillis(refreshDelay);
     }
     
     /**
@@ -1267,8 +1265,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
      * @return true if should attempt refresh, false otherwise
      */
     protected boolean shouldAttemptRefresh(@Nonnull final EntityManagementData mgmtData) {
-        final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
-        return now.isAfter(mgmtData.getRefreshTriggerTime());
+        return Instant.now().isAfter(mgmtData.getRefreshTriggerTime());
         
     }
 
@@ -1652,19 +1649,19 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
         private String entityID;
         
         /** Last update time of the associated metadata. */
-        private DateTime lastUpdateTime;
+        private Instant lastUpdateTime;
         
         /** Expiration time of the associated metadata. */
-        private DateTime expirationTime;
+        private Instant expirationTime;
         
         /** Time at which should start attempting to refresh the metadata. */
-        private DateTime refreshTriggerTime;
+        private Instant refreshTriggerTime;
         
         /** The last time in milliseconds at which the entity's backing store data was accessed. */
-        private DateTime lastAccessedTime;
+        private Instant lastAccessedTime;
         
         /** The time at which the negative lookup cache flag expires, if set. */
-        private DateTime negativeLookupCacheExpiration;
+        private Instant negativeLookupCacheExpiration;
         
         /** Read-write lock instance which governs access to the entity's backing store data. */
         private ReadWriteLock readWriteLock;
@@ -1675,9 +1672,9 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          */
         protected EntityManagementData(@Nonnull final String id) {
             entityID = Constraint.isNotNull(id, "Entity ID was null");
-            final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
-            expirationTime = now.plus(getMaxCacheDuration());
-            refreshTriggerTime = now.plus(getMaxCacheDuration());
+            final Instant now = Instant.now();
+            expirationTime = now.plusMillis(getMaxCacheDuration());
+            refreshTriggerTime = now.plusMillis(getMaxCacheDuration());
             lastAccessedTime = now;
             readWriteLock = new ReentrantReadWriteLock(true);
         }
@@ -1696,7 +1693,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @return the last update time, or null if no metadata is yet loaded for the entity
          */
-        @Nullable public DateTime getLastUpdateTime() {
+        @Nullable public Instant getLastUpdateTime() {
             return lastUpdateTime;
         }
 
@@ -1705,7 +1702,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @param dateTime the last update time
          */
-        public void setLastUpdateTime(@Nonnull final DateTime dateTime) {
+        public void setLastUpdateTime(@Nonnull final Instant dateTime) {
             lastUpdateTime = dateTime;
         }
         
@@ -1714,7 +1711,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @return the expiration time
          */
-        @Nonnull public DateTime getExpirationTime() {
+        @Nonnull public Instant getExpirationTime() {
             return expirationTime;
         }
 
@@ -1723,7 +1720,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @param dateTime the new expiration time
          */
-        public void setExpirationTime(@Nonnull final DateTime dateTime) {
+        public void setExpirationTime(@Nonnull final Instant dateTime) {
             expirationTime = Constraint.isNotNull(dateTime, "Expiration time may not be null");
         }
         
@@ -1732,7 +1729,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @return the refresh trigger time
          */
-        @Nonnull public DateTime getRefreshTriggerTime() {
+        @Nonnull public Instant getRefreshTriggerTime() {
             return refreshTriggerTime;
         }
 
@@ -1741,7 +1738,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @param dateTime the new refresh trigger time
          */
-        public void setRefreshTriggerTime(@Nonnull final DateTime dateTime) {
+        public void setRefreshTriggerTime(@Nonnull final Instant dateTime) {
             refreshTriggerTime = Constraint.isNotNull(dateTime, "Refresh trigger time may not be null");
         }
 
@@ -1750,7 +1747,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @return the time in milliseconds since the epoch
          */
-        @Nonnull public DateTime getLastAccessedTime() {
+        @Nonnull public Instant getLastAccessedTime() {
             return lastAccessedTime;
         }
         
@@ -1758,7 +1755,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * Record access of the entity's backing store data.
          */
         public void recordEntityAccess() {
-            lastAccessedTime = new DateTime(ISOChronology.getInstanceUTC());
+            lastAccessedTime = Instant.now();
         }
         
         /**
@@ -1767,8 +1764,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * @return true if active, false otherwise
          */
         public boolean isNegativeLookupCacheActive() {
-            final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
-            return negativeLookupCacheExpiration != null && now.isBefore(negativeLookupCacheExpiration);
+            return negativeLookupCacheExpiration != null && Instant.now().isBefore(negativeLookupCacheExpiration);
         }
         
         /**
@@ -1776,9 +1772,8 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * 
          * @return the time before which no further lookups for the entity will be performed
          */
-        public DateTime initNegativeLookupCache() {
-            final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
-            negativeLookupCacheExpiration = now.plus(getNegativeLookupCacheDuration());
+        public Instant initNegativeLookupCache() {
+            negativeLookupCacheExpiration = Instant.now().plusMillis(getNegativeLookupCacheDuration());
             return negativeLookupCacheExpiration;
         }
         
@@ -1807,7 +1802,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
     protected class BackingStoreCleanupSweeper extends TimerTask {
         
         /** Logger. */
-        private final Logger log = LoggerFactory.getLogger(BackingStoreCleanupSweeper.class);
+        @Nonnull private final Logger log = LoggerFactory.getLogger(BackingStoreCleanupSweeper.class);
 
         /** {@inheritDoc} */
         @Override
@@ -1828,8 +1823,8 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          *  which hasn't been accessed within the last {@link #getMaxIdleEntityData()} milliseconds.
          */
         private void removeExpiredAndIdleMetadata() {
-            final DateTime now = new DateTime(ISOChronology.getInstanceUTC());
-            final DateTime earliestValidLastAccessed = now.minus(getMaxIdleEntityData());
+            final Instant now = Instant.now();
+            final Instant earliestValidLastAccessed = now.minusMillis(getMaxIdleEntityData());
             
             final DynamicEntityBackingStore backingStore = getBackingStore();
             final Map<String, List<EntityDescriptor>> indexedDescriptors = backingStore.getIndexedDescriptors();
@@ -1862,7 +1857,7 @@ public abstract class AbstractDynamicMetadataResolver extends AbstractMetadataRe
          * @return true if the entity is expired or exceeds the max idle time, false otherwise
          */
         private boolean isRemoveData(@Nonnull final EntityManagementData mgmtData, 
-                @Nonnull final DateTime now, @Nonnull final DateTime earliestValidLastAccessed) {
+                @Nonnull final Instant now, @Nonnull final Instant earliestValidLastAccessed) {
             if (isRemoveIdleEntityData() && mgmtData.getLastAccessedTime().isBefore(earliestValidLastAccessed)) {
                 log.debug("{} Entity metadata exceeds maximum idle time, removing: {}", 
                         getLogPrefix(), mgmtData.getEntityID());
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractReloadingMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractReloadingMetadataResolver.java
index e199071..370f172 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractReloadingMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/AbstractReloadingMetadataResolver.java
@@ -21,15 +21,14 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.time.Instant;
+import java.time.ZoneId;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver;
@@ -89,23 +88,23 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
     @Duration @Positive private long minRefreshDelay = 300000;
 
     /** Time when the currently cached metadata file expires. */
-    private DateTime expirationTime;
+    private Instant expirationTime;
     
     /** Impending expiration warning threshold for metadata refresh, in milliseconds. 
      * Default value: 0ms (disabled). */
     @Duration @Positive private long expirationWarningThreshold;
 
     /** Last time the metadata was updated. */
-    private DateTime lastUpdate;
+    private Instant lastUpdate;
 
     /** Last time a refresh cycle occurred. */
-    private DateTime lastRefresh;
+    private Instant lastRefresh;
 
     /** Next time a refresh cycle will occur. */
-    private DateTime nextRefresh;
+    private Instant nextRefresh;
     
     /** Last time a successful refresh cycle occurred. */
-    private DateTime lastSuccessfulRefresh;
+    private Instant lastSuccessfulRefresh;
 
     /** Flag indicating whether last refresh cycle was successful. */
     private Boolean wasLastRefreshSuccess;
@@ -126,8 +125,6 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * @param backgroundTaskTimer time used to schedule background refresh tasks
      */
     protected AbstractReloadingMetadataResolver(@Nullable final Timer backgroundTaskTimer) {
-        super();
-        
         setCacheSourceMetadata(true);
         
         if (backgroundTaskTimer == null) {
@@ -157,23 +154,23 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * 
      * @return time when the currently cached metadata expires, or null if no metadata is cached
      */
-    public DateTime getExpirationTime() {
+    public Instant getExpirationTime() {
         return expirationTime;
     }
 
     /** {@inheritDoc} */
     @Override
-    @Nullable public DateTime getLastUpdate() {
+    @Nullable public Instant getLastUpdate() {
         return lastUpdate;
     }
 
     /** {@inheritDoc} */
-    @Override @Nullable public DateTime getLastRefresh() {
+    @Override @Nullable public Instant getLastRefresh() {
         return lastRefresh;
     }
     
     /** {@inheritDoc} */
-    @Nullable public DateTime getLastSuccessfulRefresh() {
+    @Nullable public Instant getLastSuccessfulRefresh() {
         return lastSuccessfulRefresh;
     }
 
@@ -187,7 +184,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * 
      * @return time when the next refresh cycle will occur
      */
-    public DateTime getNextRefresh() {
+    public Instant getNextRefresh() {
         return nextRefresh;
     }
 
@@ -328,7 +325,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      */
     @Override
     public synchronized void refresh() throws ResolverException {
-        DateTime now = null;
+        Instant now = null;
         String mdId = null;
         trackRefreshSuccess = false;
 
@@ -344,7 +341,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
                 refreshMetadataTask.cancel();
             }
             
-            now = new DateTime(ISOChronology.getInstanceUTC());
+            now = Instant.now();
             mdId = getMetadataIdentifier();
 
             log.debug("{} Beginning refresh of metadata from '{}'", getLogPrefix(), mdId);
@@ -359,7 +356,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
             }
         } catch (final Throwable t) {
             trackRefreshSuccess = false;
-            nextRefresh = new DateTime(ISOChronology.getInstanceUTC()).plus(computeNextRefreshDelay(null));
+            nextRefresh = Instant.now().plusMillis(computeNextRefreshDelay(null));
             if (t instanceof Exception) {
                 log.error("{} Error occurred while attempting to refresh metadata from '{}'", getLogPrefix(), mdId);
                 throw new ResolverException((Exception) t);
@@ -379,11 +376,11 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
             }
             
             refreshMetadataTask = new RefreshMetadataTask();
-            final long nextRefreshDelay = nextRefresh.getMillis() - System.currentTimeMillis();
+            final long nextRefreshDelay = nextRefresh.toEpochMilli() - System.currentTimeMillis();
             taskTimer.schedule(refreshMetadataTask, nextRefreshDelay);
             log.info("{} Next refresh cycle for metadata provider '{}' will occur on '{}' ('{}' local time)",
                     new Object[] {getLogPrefix(), mdId, nextRefresh, 
-                            nextRefresh.toDateTime(DateTimeZone.getDefault()),});
+                            nextRefresh.atZone(ZoneId.systemDefault()),});
             lastRefresh = now;
         }
     }
@@ -393,7 +390,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      *
      * @param now the current date/time
      */
-    private void logCachedMetadataExpiration(@Nonnull final DateTime now) {
+    private void logCachedMetadataExpiration(@Nonnull final Instant now) {
         final String mdId = getMetadataIdentifier();
         final XMLObject cached = getBackingStore().getCachedOriginalMetadata();
         if (cached != null && !isValid(cached)) {
@@ -403,7 +400,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
             final TimeBoundSAMLObject timebound = (TimeBoundSAMLObject) cached;
             if (isRequireValidMetadata() && timebound.getValidUntil() != null) {
                 if (getExpirationWarningThreshold() > 0 
-                        && timebound.getValidUntil().isBefore(now.plus(getExpirationWarningThreshold()))) {
+                        && timebound.getValidUntil().isBefore(now.plusMillis(getExpirationWarningThreshold()))) {
                     log.warn("{} Metadata root from '{}' currently live (post-refresh) will expire "
                             + "within the configured threshhold at '{}'",
                             getLogPrefix(), mdId, timebound.getValidUntil());
@@ -459,17 +456,17 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * 
      * @throws ResolverException throw is there is a problem process the cached metadata
      */
-    protected void processCachedMetadata(final String metadataIdentifier, final DateTime refreshStart)
+    protected void processCachedMetadata(final String metadataIdentifier, final Instant refreshStart)
             throws ResolverException {
         log.debug("{} Computing new expiration time for cached metadata from '{}'", getLogPrefix(), metadataIdentifier);
-        final DateTime metadataExpirationTime = 
+        final Instant metadataExpirationTime = 
                 SAML2Support.getEarliestExpiration(getBackingStore().getCachedOriginalMetadata(),
-                refreshStart.plus(getMaxRefreshDelay()), refreshStart);
+                refreshStart.plusMillis(getMaxRefreshDelay()), refreshStart);
 
         trackRefreshSuccess = true;
         expirationTime = metadataExpirationTime;
         final long nextRefreshDelay = computeNextRefreshDelay(expirationTime);
-        nextRefresh = new DateTime(ISOChronology.getInstanceUTC()).plus(nextRefreshDelay);
+        nextRefresh = Instant.now().plusMillis(nextRefreshDelay);
     }
 
     /**
@@ -482,7 +479,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * 
      * @throws ResolverException thrown if there is a problem unmarshalling or filtering the new metadata
      */
-    protected void processNewMetadata(final String metadataIdentifier, final DateTime refreshStart,
+    protected void processNewMetadata(final String metadataIdentifier, final Instant refreshStart,
             final byte[] metadataBytes) throws ResolverException {
         log.debug("{} Unmarshalling metadata from '{}'", getLogPrefix(), metadataIdentifier);
         final XMLObject metadata = unmarshallMetadata(metadataBytes);
@@ -504,12 +501,12 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * @param metadataBytes raw bytes of the new metadata document
      * @param metadata new metadata document unmarshalled
      */
-    protected void processPreExpiredMetadata(final String metadataIdentifier, final DateTime refreshStart,
+    protected void processPreExpiredMetadata(final String metadataIdentifier, final Instant refreshStart,
             final byte[] metadataBytes, final XMLObject metadata) {
         log.warn("{} Entire metadata document from '{}' was expired at time of loading, " 
                 + "previous metadata retained, if any", getLogPrefix(), metadataIdentifier);
 
-        nextRefresh = new DateTime(ISOChronology.getInstanceUTC()).plus(computeNextRefreshDelay(null));
+        nextRefresh = Instant.now().plusMillis(computeNextRefreshDelay(null));
         trackRefreshSuccess = false;
     }
 
@@ -524,7 +521,7 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * 
      * @throws ResolverException thrown if there s a problem processing the metadata
      */
-    protected void processNonExpiredMetadata(final String metadataIdentifier, final DateTime refreshStart,
+    protected void processNonExpiredMetadata(final String metadataIdentifier, final Instant refreshStart,
             final byte[] metadataBytes, final XMLObject metadata) throws ResolverException {
         final Document metadataDom = metadata.getDOM().getOwnerDocument();
 
@@ -549,8 +546,9 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
         log.debug("{} Computing expiration time for metadata from '{}'", getLogPrefix(), metadataIdentifier);
         // Note: As noted in its Javadocs, technically this method can sometimes return null, but won't in this case
         // since the candidate time (2nd arg) is not null.
-        final DateTime metadataExpirationTime = SAML2Support.getEarliestExpiration(
-                newBackingStore.getCachedOriginalMetadata(), refreshStart.plus(getMaxRefreshDelay()), refreshStart);
+        final Instant metadataExpirationTime = SAML2Support.getEarliestExpiration(
+                newBackingStore.getCachedOriginalMetadata(), refreshStart.plusMillis(getMaxRefreshDelay()),
+                refreshStart);
         log.debug("{} Expiration of metadata from '{}' will occur at {}", getLogPrefix(), metadataIdentifier, 
                 metadataExpirationTime.toString());
 
@@ -561,15 +559,17 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
         lastUpdate = refreshStart;
         trackRefreshSuccess = true;
         
+        final Instant now = Instant.now();
+        
         final long nextRefreshDelay;
-        if (metadataExpirationTime.isBeforeNow()) {
-            expirationTime = new DateTime(ISOChronology.getInstanceUTC()).plus(getMinRefreshDelay());
+        if (metadataExpirationTime.isBefore(now)) {
+            expirationTime = now.plusMillis(getMinRefreshDelay());
             nextRefreshDelay = getMaxRefreshDelay();
         } else {
             expirationTime = metadataExpirationTime;
             nextRefreshDelay = computeNextRefreshDelay(expirationTime);
         }
-        nextRefresh = new DateTime(ISOChronology.getInstanceUTC()).plus(nextRefreshDelay);
+        nextRefresh = now.plusMillis(nextRefreshDelay);
 
         log.info("{} New metadata successfully loaded for '{}'", getLogPrefix(), getMetadataIdentifier());
     }
@@ -601,12 +601,12 @@ public abstract class AbstractReloadingMetadataResolver extends AbstractBatchMet
      * 
      * @return delay, in milliseconds, until the next refresh time
      */
-    protected long computeNextRefreshDelay(final DateTime expectedExpiration) {
-        final long now = new DateTime(ISOChronology.getInstanceUTC()).getMillis();
+    protected long computeNextRefreshDelay(final Instant expectedExpiration) {
+        final long now = System.currentTimeMillis();
 
         long expireInstant = 0;
         if (expectedExpiration != null) {
-            expireInstant = expectedExpiration.toDateTime(ISOChronology.getInstanceUTC()).getMillis();
+            expireInstant = expectedExpiration.toEpochMilli();
         }
         long refreshDelay = (long) ((expireInstant - now) * getRefreshDelayFactor());
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/CompositeMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/CompositeMetadataResolver.java
index 239f6dc..9fde86d 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/CompositeMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/CompositeMetadataResolver.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.metadata.resolver.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -34,7 +35,6 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.metadata.resolver.ClearableMetadataResolver;
 import org.opensaml.saml.metadata.resolver.MetadataResolver;
 import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver;
@@ -182,11 +182,11 @@ public class CompositeMetadataResolver extends AbstractIdentifiedInitializableCo
 
     /** {@inheritDoc} */
     @Override
-    @Nullable public DateTime getLastUpdate() {
-        DateTime ret = null;
+    @Nullable public Instant getLastUpdate() {
+        Instant ret = null;
         for (final MetadataResolver resolver : resolvers) {
             if (resolver instanceof RefreshableMetadataResolver) {
-                final DateTime lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate();
+                final Instant lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate();
                 if (ret == null || ret.isBefore(lastUpdate)) {
                     ret = lastUpdate;
                 }
@@ -198,11 +198,11 @@ public class CompositeMetadataResolver extends AbstractIdentifiedInitializableCo
 
     /** {@inheritDoc} */
     @Override
-    @Nullable public DateTime getLastRefresh() {
-        DateTime ret = null;
+    @Nullable public Instant getLastRefresh() {
+        Instant ret = null;
         for (final MetadataResolver resolver : resolvers) {
             if (resolver instanceof RefreshableMetadataResolver) {
-                final DateTime lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh();
+                final Instant lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh();
                 if (ret == null || ret.isBefore(lastRefresh)) {
                     ret = lastRefresh;
                 }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolver.java
index 1d69110..01877c1 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolver.java
@@ -20,6 +20,7 @@ package org.opensaml.saml.metadata.resolver.impl;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.time.Instant;
 import java.util.Timer;
 
 import javax.annotation.Nonnull;
@@ -32,7 +33,6 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
 import org.apache.http.client.HttpClient;
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -317,7 +317,7 @@ public class FileBackedHTTPMetadataResolver extends HTTPMetadataResolver {
 
     /** {@inheritDoc} */
     @Override
-    protected long computeNextRefreshDelay(final DateTime expectedExpiration) {
+    protected long computeNextRefreshDelay(final Instant expectedExpiration) {
         if (initializing && initializedFromBackupFile) {
             log.debug("{} Detected initialization from backup file, scheduling next refresh from HTTP in {}ms", 
                     getLogPrefix(), getBackupFileInitNextRefreshDelay());
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FilesystemMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FilesystemMetadataResolver.java
index de9a314..c649b8f 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FilesystemMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/FilesystemMetadataResolver.java
@@ -20,6 +20,7 @@ package org.opensaml.saml.metadata.resolver.impl;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.time.Instant;
 import java.util.Timer;
 
 import javax.annotation.Nonnull;
@@ -29,8 +30,6 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -116,8 +115,7 @@ public class FilesystemMetadataResolver extends AbstractReloadingMetadataResolve
     protected byte[] fetchMetadata() throws ResolverException {
         try {
             validateMetadataFile(metadataFile);
-            final DateTime metadataUpdateTime =
-                     new DateTime(metadataFile.lastModified(), ISOChronology.getInstanceUTC());
+            final Instant metadataUpdateTime = Instant.ofEpochMilli(metadataFile.lastModified());
             if (getLastRefresh() == null || getLastUpdate() == null || metadataUpdateTime.isAfter(getLastUpdate())) {
                 return inputstreamToByteArray(new FileInputStream(metadataFile));
             }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/ResourceBackedMetadataResolver.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/ResourceBackedMetadataResolver.java
index 986f3fa..d941ea1 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/ResourceBackedMetadataResolver.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/resolver/impl/ResourceBackedMetadataResolver.java
@@ -18,9 +18,9 @@
 package org.opensaml.saml.metadata.resolver.impl;
 
 import java.io.IOException;
+import java.time.Instant;
 import java.util.Timer;
 
-import org.joda.time.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -92,7 +92,7 @@ public class ResourceBackedMetadataResolver extends AbstractReloadingMetadataRes
     @Override
     protected byte[] fetchMetadata() throws ResolverException {
         try {
-            final DateTime metadataUpdateTime = new DateTime(metadataResource.lastModified());
+            final Instant metadataUpdateTime = Instant.ofEpochMilli(metadataResource.lastModified());
             log.debug("{} Resource {} was last modified {}", 
                     getLogPrefix(), metadataResource.getDescription(), metadataUpdateTime);
             if (getLastRefresh() == null || metadataUpdateTime.isAfter(getLastRefresh())) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionImpl.java
index 33cdf56..a6c08e8 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionImpl.java
@@ -17,13 +17,13 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 import org.opensaml.saml.common.AbstractSignableSAMLObject;
@@ -53,7 +53,7 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
     private String issuer;
 
     /** Object version of the <code> IssueInstant </code> attribute. */
-    private DateTime issueInstant;
+    private Instant issueInstant;
 
     /** (Possibly null) Singleton object version of the <code> Conditions </code> element. */
     private Conditions conditions;
@@ -115,12 +115,12 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
     }
 
     /** {@inheritDoc} */
-    public DateTime getIssueInstant() {
+    public Instant getIssueInstant() {
         return this.issueInstant;
     }
 
     /** {@inheritDoc} */
-    public void setIssueInstant(final DateTime instant) {
+    public void setIssueInstant(final Instant instant) {
         issueInstant = prepareForAssignment(issueInstant, instant);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionMarshaller.java
index 1d76af6..ea1c80d 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionMarshaller.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
-import org.joda.time.format.ISODateTimeFormat;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectMarshaller;
+import org.opensaml.saml.config.SAMLConfigurationSupport;
 import org.opensaml.saml.saml1.core.Assertion;
 import org.w3c.dom.Element;
 
@@ -47,7 +47,8 @@ public class AssertionMarshaller extends AbstractSAMLObjectMarshaller {
         }
 
         if (assertion.getIssueInstant() != null) {
-            final String date = ISODateTimeFormat.dateTime().print(assertion.getIssueInstant());
+            final String date =
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(assertion.getIssueInstant());
             domElement.setAttributeNS(null, Assertion.ISSUEINSTANT_ATTRIB_NAME, date);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionUnmarshaller.java
index 4a715cc..adb120a 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AssertionUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -80,7 +80,7 @@ public class AssertionUnmarshaller extends AbstractSAMLObjectUnmarshaller {
                 assertion.setIssuer(attribute.getValue());
             } else if (Assertion.ISSUEINSTANT_ATTRIB_NAME.equals(attribute.getLocalName())
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                assertion.setIssueInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                assertion.setIssueInstant(Instant.parse(attribute.getValue()));
             } else if (Assertion.MAJORVERSION_ATTRIB_NAME.equals(attribute.getLocalName())) {
                 final int major;
                 try {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementImpl.java
index b2d0274..46f29ae 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementImpl.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.XMLObjectChildrenList;
 import org.opensaml.saml.saml1.core.AuthenticationStatement;
@@ -37,7 +37,7 @@ public class AuthenticationStatementImpl extends SubjectStatementImpl implements
     private String authenticationMethod;
 
     /** Contains the AuthenticationMethod attribute contents. */
-    private DateTime authenticationInstant;
+    private Instant authenticationInstant;
 
     /** Contains the SubjectLocality subelement. */
     private SubjectLocality subjectLocality;
@@ -69,12 +69,12 @@ public class AuthenticationStatementImpl extends SubjectStatementImpl implements
     }
 
     /** {@inheritDoc} */
-    public DateTime getAuthenticationInstant() {
+    public Instant getAuthenticationInstant() {
         return authenticationInstant;
     }
 
     /** {@inheritDoc} */
-    public void setAuthenticationInstant(final DateTime instant) {
+    public void setAuthenticationInstant(final Instant instant) {
         authenticationInstant = prepareForAssignment(authenticationInstant, instant);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementMarshaller.java
index f0b7c01..4a74838 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementMarshaller.java
@@ -39,7 +39,7 @@ public class AuthenticationStatementMarshaller extends SubjectStatementMarshalle
         }
 
         if (authenticationStatement.getAuthenticationInstant() != null) {
-            final String value = SAMLConfigurationSupport.getSAMLDateFormatter().print(
+            final String value = SAMLConfigurationSupport.getSAMLDateFormatter().format(
                     authenticationStatement.getAuthenticationInstant());
             domElement.setAttributeNS(null, AuthenticationStatement.AUTHENTICATIONINSTANT_ATTRIB_NAME, value);
         }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementUnmarshaller.java
index 25005d2..305d3be 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.saml1.core.AuthenticationStatement;
@@ -55,8 +55,7 @@ public class AuthenticationStatementUnmarshaller extends SubjectStatementUnmarsh
         if (attribute.getNamespaceURI() == null) {
             if (AuthenticationStatement.AUTHENTICATIONINSTANT_ATTRIB_NAME.equals(attribute.getLocalName())
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                final DateTime value = new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC());
-                authenticationStatement.setAuthenticationInstant(value);
+                authenticationStatement.setAuthenticationInstant(Instant.parse(attribute.getValue()));
             } else if (AuthenticationStatement.AUTHENTICATIONMETHOD_ATTRIB_NAME.equals(attribute.getLocalName())) {
                 authenticationStatement.setAuthenticationMethod(attribute.getValue());
             } else {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsImpl.java
index d1206db..e210160 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsImpl.java
@@ -17,13 +17,13 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 import org.opensaml.saml.common.AbstractSAMLObject;
@@ -39,10 +39,10 @@ import org.opensaml.saml.saml1.core.DoNotCacheCondition;
 public class ConditionsImpl extends AbstractSAMLObject implements Conditions {
 
     /** Value saved in the NotBefore attribute. */
-    private DateTime notBefore;
+    private Instant notBefore;
 
     /** Value saved in the NotOnOrAfter attribute. */
-    private DateTime notOnOrAfter;
+    private Instant notOnOrAfter;
 
     /** Set containing all the Conditions. */
     private final IndexedXMLObjectChildrenList<Condition> conditions;
@@ -60,22 +60,22 @@ public class ConditionsImpl extends AbstractSAMLObject implements Conditions {
     }
 
     /** {@inheritDoc} */
-    public DateTime getNotBefore() {
+    public Instant getNotBefore() {
         return notBefore;
     }
 
     /** {@inheritDoc} */
-    public void setNotBefore(final DateTime dt) {
+    public void setNotBefore(final Instant dt) {
         notBefore = prepareForAssignment(notBefore, dt);
     }
 
     /** {@inheritDoc} */
-    public DateTime getNotOnOrAfter() {
+    public Instant getNotOnOrAfter() {
         return notOnOrAfter;
     }
 
     /** {@inheritDoc} */
-    public void setNotOnOrAfter(final DateTime dt) {
+    public void setNotOnOrAfter(final Instant dt) {
         notOnOrAfter = prepareForAssignment(notOnOrAfter, dt);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsMarshaller.java
index a601e95..87f6c53 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsMarshaller.java
@@ -36,12 +36,12 @@ public class ConditionsMarshaller extends AbstractSAMLObjectMarshaller {
         final Conditions conditions = (Conditions) samlElement;
 
         if (conditions.getNotBefore() != null) {
-            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().print(conditions.getNotBefore());
+            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().format(conditions.getNotBefore());
             domElement.setAttributeNS(null, Conditions.NOTBEFORE_ATTRIB_NAME, date);
         }
 
         if (conditions.getNotOnOrAfter() != null) {
-            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().print(conditions.getNotOnOrAfter());
+            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().format(conditions.getNotOnOrAfter());
             domElement.setAttributeNS(null, Conditions.NOTONORAFTER_ATTRIB_NAME, date);
         }
     }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsUnmarshaller.java
index 79ebe30..0655b44 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ConditionsUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -53,10 +53,10 @@ public class ConditionsUnmarshaller extends AbstractSAMLObjectUnmarshaller {
         if (attribute.getNamespaceURI() == null) {
             if (Conditions.NOTBEFORE_ATTRIB_NAME.equals(attribute.getLocalName())
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                conditions.setNotBefore(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                conditions.setNotBefore(Instant.parse(attribute.getValue()));
             } else if (Conditions.NOTONORAFTER_ATTRIB_NAME.equals(attribute.getLocalName())
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                conditions.setNotOnOrAfter(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                conditions.setNotOnOrAfter(Instant.parse(attribute.getValue()));
             } else {
                 super.processAttribute(samlObject, attribute);
             }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeImpl.java
index 90aa249..67cbc7a 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeImpl.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.XMLObjectChildrenList;
 import org.opensaml.saml.common.AbstractSignableSAMLObject;
@@ -38,7 +38,7 @@ public abstract class RequestAbstractTypeImpl extends AbstractSignableSAMLObject
     private String id;
 
     /** Contains the IssueInstant. */
-    private DateTime issueInstant;
+    private Instant issueInstant;
 
     /** Version of this SAML message. */
     private SAMLVersion version;
@@ -83,12 +83,12 @@ public abstract class RequestAbstractTypeImpl extends AbstractSignableSAMLObject
     }
 
     /** {@inheritDoc} */
-    public DateTime getIssueInstant() {
+    public Instant getIssueInstant() {
         return issueInstant;
     }
 
     /** {@inheritDoc} */
-    public void setIssueInstant(final DateTime instant) {
+    public void setIssueInstant(final Instant instant) {
         this.issueInstant = prepareForAssignment(this.issueInstant, instant);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeMarshaller.java
index e0cc748..5617c18 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeMarshaller.java
@@ -47,7 +47,7 @@ public class RequestAbstractTypeMarshaller extends AbstractSAMLObjectMarshaller
         }
 
         if (request.getIssueInstant() != null) {
-            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().print(request.getIssueInstant());
+            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().format(request.getIssueInstant());
             domElement.setAttributeNS(null, RequestAbstractType.ISSUEINSTANT_ATTRIB_NAME, date);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeUnmarshaller.java
index 20d6125..320fc17 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/RequestAbstractTypeUnmarshaller.java
@@ -21,10 +21,10 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -81,8 +81,7 @@ public abstract class RequestAbstractTypeUnmarshaller extends AbstractSAMLObject
                 request.setID(attribute.getValue());
             } else if (RequestAbstractType.ISSUEINSTANT_ATTRIB_NAME.equals(attribute.getLocalName())
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                final DateTime cal = new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC());
-                request.setIssueInstant(cal);
+                request.setIssueInstant(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(RequestAbstractType.MAJORVERSION_ATTRIB_NAME)) {
                 final int major;
                 try {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeImpl.java
index e06d36b..0730c05 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeImpl.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.AbstractSignableSAMLObject;
 import org.opensaml.saml.common.SAMLVersion;
@@ -42,7 +42,7 @@ public abstract class ResponseAbstractTypeImpl extends AbstractSignableSAMLObjec
     private String inResponseTo;
 
     /** Contents of the IssueInstant attribute. */
-    private DateTime issueInstant;
+    private Instant issueInstant;
 
     /** Contents of the Recipient attribute. */
     private String recipient;
@@ -93,14 +93,14 @@ public abstract class ResponseAbstractTypeImpl extends AbstractSignableSAMLObjec
     }
 
     /** {@inheritDoc} */
-    public DateTime getIssueInstant() {
+    public Instant getIssueInstant() {
 
         return issueInstant;
     }
 
     /** {@inheritDoc} */
-    public void setIssueInstant(final DateTime date) {
-        this.issueInstant = prepareForAssignment(this.issueInstant, date);
+    public void setIssueInstant(final Instant date) {
+        issueInstant = prepareForAssignment(issueInstant, date);
     }
 
     /** {@inheritDoc} */
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeMarshaller.java
index 9ca5a76..7e1711f 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeMarshaller.java
@@ -52,7 +52,7 @@ public abstract class ResponseAbstractTypeMarshaller extends AbstractSAMLObjectM
         }
 
         if (response.getIssueInstant() != null) {
-            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().print(response.getIssueInstant());
+            final String date = SAMLConfigurationSupport.getSAMLDateFormatter().format(response.getIssueInstant());
             domElement.setAttributeNS(null, ResponseAbstractType.ISSUEINSTANT_ATTRIB_NAME, date);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeUnmarshaller.java
index f924530..df467f8 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/core/impl/ResponseAbstractTypeUnmarshaller.java
@@ -21,10 +21,10 @@
 
 package org.opensaml.saml.saml1.core.impl;
 
+import java.time.Instant;
+
 import javax.annotation.Nonnull;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -81,7 +81,7 @@ public abstract class ResponseAbstractTypeUnmarshaller extends AbstractSAMLObjec
                 response.setInResponseTo(attribute.getValue());
             } else if (attribute.getLocalName().equals(ResponseAbstractType.ISSUEINSTANT_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                response.setIssueInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                response.setIssueInstant(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(ResponseAbstractType.MAJORVERSION_ATTRIB_NAME)) {
                 final int major;
                 try {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/profile/impl/AddResponseShell.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/profile/impl/AddResponseShell.java
index e77e2b8..dee7261 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/profile/impl/AddResponseShell.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml1/profile/impl/AddResponseShell.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.saml1.profile.impl;
 
+import java.time.Instant;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -27,8 +28,6 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
 import net.shibboleth.utilities.java.support.security.SecureRandomIdentifierGenerationStrategy;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectBuilderFactory;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.messaging.context.MessageContext;
@@ -149,7 +148,7 @@ public class AddResponseShell extends AbstractProfileAction {
         final Response response = responseBuilder.buildObject();
 
         response.setID(idGenerator.generateIdentifier());
-        response.setIssueInstant(new DateTime(ISOChronology.getInstanceUTC()));
+        response.setIssueInstant(Instant.now());
         response.setStatus(status);
         response.setVersion(SAMLVersion.VERSION_11);
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java
index d8a047c..a6c3cdb 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidator.java
@@ -19,6 +19,7 @@ package org.opensaml.saml.saml2.assertion.impl;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Set;
 
@@ -27,8 +28,6 @@ import javax.annotation.concurrent.ThreadSafe;
 
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.saml.common.assertion.AssertionValidationException;
 import org.opensaml.saml.common.assertion.ValidationContext;
 import org.opensaml.saml.common.assertion.ValidationResult;
@@ -125,9 +124,8 @@ public abstract class AbstractSubjectConfirmationValidator implements SubjectCon
     @Nonnull protected ValidationResult validateNotBefore(@Nonnull final SubjectConfirmation confirmation, 
             @Nonnull final Assertion assertion, @Nonnull final ValidationContext context) 
                     throws AssertionValidationException {
-        final DateTime skewedNow = new DateTime(ISOChronology.getInstanceUTC()).plus(SAML20AssertionValidator
-                .getClockSkew(context));
-        final DateTime notBefore = confirmation.getSubjectConfirmationData().getNotBefore();
+        final Instant skewedNow = Instant.now().plusMillis(SAML20AssertionValidator.getClockSkew(context));
+        final Instant notBefore = confirmation.getSubjectConfirmationData().getNotBefore();
         
         log.debug("Evaluating SubjectConfirmationData NotBefore '{}' against 'skewed now' time '{}'",
                 notBefore, skewedNow);
@@ -157,9 +155,8 @@ public abstract class AbstractSubjectConfirmationValidator implements SubjectCon
     @Nonnull protected ValidationResult validateNotOnOrAfter(@Nonnull final SubjectConfirmation confirmation, 
             @Nonnull final Assertion assertion, @Nonnull final ValidationContext context) 
                     throws AssertionValidationException {
-        final DateTime skewedNow = new DateTime(ISOChronology.getInstanceUTC()).minus(SAML20AssertionValidator
-                .getClockSkew(context));
-        final DateTime notOnOrAfter = confirmation.getSubjectConfirmationData().getNotOnOrAfter();
+        final Instant skewedNow = Instant.now().minusMillis(SAML20AssertionValidator.getClockSkew(context));
+        final Instant notOnOrAfter = confirmation.getSubjectConfirmationData().getNotOnOrAfter();
         
         log.debug("Evaluating SubjectConfirmationData NotOnOrAfter '{}' against 'skewed now' time '{}'",
                 notOnOrAfter, skewedNow);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java
index 72f7003..338dcf1 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/binding/decoding/impl/HTTPArtifactDecoder.java
@@ -17,14 +17,13 @@
 
 package org.opensaml.saml.saml2.binding.decoding.impl;
 
+import java.time.Instant;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.util.XMLObjectSupport;
 import org.opensaml.messaging.MessageException;
 import org.opensaml.messaging.context.InOutOperationContext;
@@ -522,7 +521,7 @@ public class HTTPArtifactDecoder extends BaseHttpServletRequestXMLMessageDecoder
         
         request.setID(idStrategy.generateIdentifier(true));
         request.setDestination(endpoint);
-        request.setIssueInstant(new DateTime(ISOChronology.getInstanceUTC()));
+        request.setIssueInstant(Instant.now());
         request.setIssuer(buildIssuer(selfEntityID));
         
         return request;
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionImpl.java
index 17cdb73..2df79bf 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionImpl.java
@@ -21,13 +21,13 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 import org.opensaml.saml.common.AbstractSignableSAMLObject;
@@ -52,7 +52,7 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
     private SAMLVersion version;
 
     /** Issue Instant of the assertion. */
-    private DateTime issueInstant;
+    private Instant issueInstant;
 
     /** ID of the assertion. */
     private String id;
@@ -92,17 +92,17 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
 
     /** {@inheritDoc} */
     public void setVersion(final SAMLVersion newVersion) {
-        this.version = prepareForAssignment(this.version, newVersion);
+        version = prepareForAssignment(version, newVersion);
     }
 
     /** {@inheritDoc} */
-    public DateTime getIssueInstant() {
+    public Instant getIssueInstant() {
         return issueInstant;
     }
 
     /** {@inheritDoc} */
-    public void setIssueInstant(final DateTime newIssueInstance) {
-        this.issueInstant = prepareForAssignment(this.issueInstant, newIssueInstance);
+    public void setIssueInstant(final Instant newIssueInstance) {
+        issueInstant = prepareForAssignment(issueInstant, newIssueInstance);
     }
 
     /** {@inheritDoc} */
@@ -112,9 +112,9 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
 
     /** {@inheritDoc} */
     public void setID(final String newID) {
-        final String oldID = this.id;
-        this.id = prepareForAssignment(this.id, newID);
-        registerOwnID(oldID, this.id);
+        final String oldID = id;
+        id = prepareForAssignment(id, newID);
+        registerOwnID(oldID, id);
     }
 
     /** {@inheritDoc} */
@@ -124,7 +124,7 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
 
     /** {@inheritDoc} */
     public void setIssuer(final Issuer newIssuer) {
-        this.issuer = prepareForAssignment(this.issuer, newIssuer);
+        issuer = prepareForAssignment(issuer, newIssuer);
     }
 
     /** {@inheritDoc} */
@@ -134,7 +134,7 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
 
     /** {@inheritDoc} */
     public void setSubject(final Subject newSubject) {
-        this.subject = prepareForAssignment(this.subject, newSubject);
+        subject = prepareForAssignment(subject, newSubject);
     }
 
     /** {@inheritDoc} */
@@ -144,7 +144,7 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
 
     /** {@inheritDoc} */
     public void setConditions(final Conditions newConditions) {
-        this.conditions = prepareForAssignment(this.conditions, newConditions);
+        conditions = prepareForAssignment(conditions, newConditions);
     }
 
     /** {@inheritDoc} */
@@ -154,7 +154,7 @@ public class AssertionImpl extends AbstractSignableSAMLObject implements Asserti
 
     /** {@inheritDoc} */
     public void setAdvice(final Advice newAdvice) {
-        this.advice = prepareForAssignment(this.advice, newAdvice);
+        advice = prepareForAssignment(advice, newAdvice);
     }
 
     /** {@inheritDoc} */
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionMarshaller.java
index df8d381..47286d4 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionMarshaller.java
@@ -44,7 +44,7 @@ public class AssertionMarshaller extends AbstractSAMLObjectMarshaller {
 
         if (assertion.getIssueInstant() != null) {
             final String issueInstantStr =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(assertion.getIssueInstant());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(assertion.getIssueInstant());
             domElement.setAttributeNS(null, Assertion.ISSUE_INSTANT_ATTRIB_NAME, issueInstantStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionUnmarshaller.java
index df0792b..03ad2be 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AssertionUnmarshaller.java
@@ -21,8 +21,8 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -73,7 +73,7 @@ public class AssertionUnmarshaller extends AbstractSAMLObjectUnmarshaller {
                 assertion.setVersion(parseSAMLVersion(attribute));
             } else if (attribute.getLocalName().equals(Assertion.ISSUE_INSTANT_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                assertion.setIssueInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                assertion.setIssueInstant(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(Assertion.ID_ATTRIB_NAME)) {
                 assertion.setID(attribute.getValue());
                 attribute.getOwnerElement().setIdAttributeNode(attribute, true);
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementImpl.java
index 7c3d76a..8bdf389 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementImpl.java
@@ -21,11 +21,11 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.AbstractSAMLObject;
 import org.opensaml.saml.saml2.core.AuthnContext;
@@ -44,13 +44,13 @@ public class AuthnStatementImpl extends AbstractSAMLObject implements AuthnState
     private AuthnContext authnContext;
 
     /** Time of the authentication. */
-    private DateTime authnInstant;
+    private Instant authnInstant;
 
     /** Index of the session. */
     private String sessionIndex;
 
     /** Time at which the session ends. */
-    private DateTime sessionNotOnOrAfter;
+    private Instant sessionNotOnOrAfter;
 
     /**
      * Constructor.
@@ -85,12 +85,12 @@ public class AuthnStatementImpl extends AbstractSAMLObject implements AuthnState
     }
 
     /** {@inheritDoc} */
-    public DateTime getAuthnInstant() {
+    public Instant getAuthnInstant() {
         return authnInstant;
     }
 
     /** {@inheritDoc} */
-    public void setAuthnInstant(final DateTime newAuthnInstant) {
+    public void setAuthnInstant(final Instant newAuthnInstant) {
         this.authnInstant = prepareForAssignment(this.authnInstant, newAuthnInstant);
     }
 
@@ -105,12 +105,12 @@ public class AuthnStatementImpl extends AbstractSAMLObject implements AuthnState
     }
 
     /** {@inheritDoc} */
-    public DateTime getSessionNotOnOrAfter() {
+    public Instant getSessionNotOnOrAfter() {
         return sessionNotOnOrAfter;
     }
 
     /** {@inheritDoc} */
-    public void setSessionNotOnOrAfter(final DateTime newSessionNotOnOrAfter) {
+    public void setSessionNotOnOrAfter(final Instant newSessionNotOnOrAfter) {
         this.sessionNotOnOrAfter = prepareForAssignment(this.sessionNotOnOrAfter, newSessionNotOnOrAfter);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementMarshaller.java
index 6c4a61d..5935e6c 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementMarshaller.java
@@ -39,7 +39,7 @@ public class AuthnStatementMarshaller extends AbstractSAMLObjectMarshaller {
         final AuthnStatement authnStatement = (AuthnStatement) samlObject;
 
         if (authnStatement.getAuthnInstant() != null) {
-            final String authnInstantStr = SAMLConfigurationSupport.getSAMLDateFormatter().print(
+            final String authnInstantStr = SAMLConfigurationSupport.getSAMLDateFormatter().format(
                     authnStatement.getAuthnInstant());
             domElement.setAttributeNS(null, AuthnStatement.AUTHN_INSTANT_ATTRIB_NAME, authnInstantStr);
         }
@@ -49,7 +49,7 @@ public class AuthnStatementMarshaller extends AbstractSAMLObjectMarshaller {
         }
 
         if (authnStatement.getSessionNotOnOrAfter() != null) {
-            final String sessionNotOnOrAfterStr = SAMLConfigurationSupport.getSAMLDateFormatter().print(
+            final String sessionNotOnOrAfterStr = SAMLConfigurationSupport.getSAMLDateFormatter().format(
                     authnStatement.getSessionNotOnOrAfter());
             domElement.setAttributeNS(null, AuthnStatement.SESSION_NOT_ON_OR_AFTER_ATTRIB_NAME, sessionNotOnOrAfterStr);
         }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementUnmarshaller.java
index 84fa12f..fc926ad 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/AuthnStatementUnmarshaller.java
@@ -21,8 +21,8 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -58,13 +58,12 @@ public class AuthnStatementUnmarshaller extends AbstractSAMLObjectUnmarshaller {
         if (attribute.getNamespaceURI() == null) {
             if (attribute.getLocalName().equals(AuthnStatement.AUTHN_INSTANT_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                authnStatement.setAuthnInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                authnStatement.setAuthnInstant(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(AuthnStatement.SESSION_INDEX_ATTRIB_NAME)) {
                 authnStatement.setSessionIndex(attribute.getValue());
             } else if (attribute.getLocalName().equals(AuthnStatement.SESSION_NOT_ON_OR_AFTER_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                authnStatement.setSessionNotOnOrAfter(new DateTime(attribute.getValue(),
-                        ISOChronology.getInstanceUTC()));
+                authnStatement.setSessionNotOnOrAfter(Instant.parse(attribute.getValue()));
             } else {
                 super.processAttribute(samlObject, attribute);
             }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsImpl.java
index 9187184..f8c6514 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsImpl.java
@@ -21,13 +21,13 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 import org.opensaml.saml.common.AbstractSAMLObject;
@@ -47,10 +47,10 @@ public class ConditionsImpl extends AbstractSAMLObject implements Conditions {
     private final IndexedXMLObjectChildrenList<Condition> conditions;
 
     /** Not Before conditions. */
-    private DateTime notBefore;
+    private Instant notBefore;
 
     /** Not On Or After conditions. */
-    private DateTime notOnOrAfter;
+    private Instant notOnOrAfter;
 
     /**
      * Constructor.
@@ -101,22 +101,22 @@ public class ConditionsImpl extends AbstractSAMLObject implements Conditions {
     }
 
     /** {@inheritDoc} */
-    public DateTime getNotBefore() {
+    public Instant getNotBefore() {
         return notBefore;
     }
 
     /** {@inheritDoc} */
-    public void setNotBefore(final DateTime newNotBefore) {
+    public void setNotBefore(final Instant newNotBefore) {
         this.notBefore = prepareForAssignment(this.notBefore, newNotBefore);
     }
 
     /** {@inheritDoc} */
-    public DateTime getNotOnOrAfter() {
+    public Instant getNotOnOrAfter() {
         return notOnOrAfter;
     }
 
     /** {@inheritDoc} */
-    public void setNotOnOrAfter(final DateTime newNotOnOrAfter) {
+    public void setNotOnOrAfter(final Instant newNotOnOrAfter) {
         this.notOnOrAfter = prepareForAssignment(this.notOnOrAfter, newNotOnOrAfter);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsMarshaller.java
index a5fcacb..d01c5c7 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsMarshaller.java
@@ -40,12 +40,12 @@ public class ConditionsMarshaller extends AbstractSAMLObjectMarshaller {
 
         if (conditions.getNotBefore() != null) {
             final String notBeforeStr =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(conditions.getNotBefore());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(conditions.getNotBefore());
             domElement.setAttributeNS(null, Conditions.NOT_BEFORE_ATTRIB_NAME, notBeforeStr);
         }
 
         if (conditions.getNotOnOrAfter() != null) {
-            final String notOnOrAfterStr = SAMLConfigurationSupport.getSAMLDateFormatter().print(
+            final String notOnOrAfterStr = SAMLConfigurationSupport.getSAMLDateFormatter().format(
                     conditions.getNotOnOrAfter());
             domElement.setAttributeNS(null, Conditions.NOT_ON_OR_AFTER_ATTRIB_NAME, notOnOrAfterStr);
         }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsUnmarshaller.java
index 564f16c..c0bb991 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/ConditionsUnmarshaller.java
@@ -21,8 +21,8 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -56,10 +56,10 @@ public class ConditionsUnmarshaller extends AbstractSAMLObjectUnmarshaller {
         if (attribute.getNamespaceURI() == null) {
             if (attribute.getLocalName().equals(Conditions.NOT_BEFORE_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                conditions.setNotBefore(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                conditions.setNotBefore(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(Conditions.NOT_ON_OR_AFTER_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                conditions.setNotOnOrAfter(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                conditions.setNotOnOrAfter(Instant.parse(attribute.getValue()));
             } else {
                 super.processAttribute(samlObject, attribute);
             }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestImpl.java
index 6746526..7c181dd 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestImpl.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.XMLObjectChildrenList;
 import org.opensaml.saml.saml2.core.BaseID;
@@ -39,7 +39,7 @@ public class LogoutRequestImpl extends RequestAbstractTypeImpl implements Logout
     private String reason;
 
     /** NotOnOrAfter attribute. */
-    private DateTime notOnOrAfter;
+    private Instant notOnOrAfter;
 
     /** BaseID child element. */
     private BaseID baseID;
@@ -78,12 +78,12 @@ public class LogoutRequestImpl extends RequestAbstractTypeImpl implements Logout
     }
 
     /** {@inheritDoc} */
-    public DateTime getNotOnOrAfter() {
+    public Instant getNotOnOrAfter() {
         return this.notOnOrAfter;
     }
 
     /** {@inheritDoc} */
-    public void setNotOnOrAfter(final DateTime newNotOnOrAfter) {
+    public void setNotOnOrAfter(final Instant newNotOnOrAfter) {
         this.notOnOrAfter = prepareForAssignment(this.notOnOrAfter, newNotOnOrAfter);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestMarshaller.java
index 0324d39..19ec256 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestMarshaller.java
@@ -42,7 +42,7 @@ public class LogoutRequestMarshaller extends RequestAbstractTypeMarshaller {
         }
 
         if (req.getNotOnOrAfter() != null) {
-            final String noaStr = SAMLConfigurationSupport.getSAMLDateFormatter().print(req.getNotOnOrAfter());
+            final String noaStr = SAMLConfigurationSupport.getSAMLDateFormatter().format(req.getNotOnOrAfter());
             domElement.setAttributeNS(null, LogoutRequest.NOT_ON_OR_AFTER_ATTRIB_NAME, noaStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestUnmarshaller.java
index fde76f3..8b0645e 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/LogoutRequestUnmarshaller.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.saml2.core.BaseID;
@@ -62,7 +62,7 @@ public class LogoutRequestUnmarshaller extends RequestAbstractTypeUnmarshaller {
                 req.setReason(attribute.getValue());
             } else if (attribute.getLocalName().equals(LogoutRequest.NOT_ON_OR_AFTER_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                req.setNotOnOrAfter(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                req.setNotOnOrAfter(Instant.parse(attribute.getValue()));
             } else {
                 super.processAttribute(samlObject, attribute);
             }
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeImpl.java
index a5bc652..72346e3 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeImpl.java
@@ -21,11 +21,11 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.AbstractSignableSAMLObject;
 import org.opensaml.saml.common.SAMLVersion;
@@ -45,7 +45,7 @@ public abstract class RequestAbstractTypeImpl extends AbstractSignableSAMLObject
     private String id;
 
     /** Date/time request was issued. */
-    private DateTime issueInstant;
+    private Instant issueInstant;
 
     /** URI of the request destination. */
     private String destination;
@@ -89,19 +89,19 @@ public abstract class RequestAbstractTypeImpl extends AbstractSignableSAMLObject
 
     /** {@inheritDoc} */
     public void setID(final String newID) {
-        final String oldID = this.id;
-        this.id = prepareForAssignment(this.id, newID);
-        registerOwnID(oldID, this.id);
+        final String oldID = id;
+        id = prepareForAssignment(id, newID);
+        registerOwnID(oldID, id);
     }
 
     /** {@inheritDoc} */
-    public DateTime getIssueInstant() {
+    public Instant getIssueInstant() {
         return issueInstant;
     }
 
     /** {@inheritDoc} */
-    public void setIssueInstant(final DateTime newIssueInstant) {
-        this.issueInstant = prepareForAssignment(this.issueInstant, newIssueInstant);
+    public void setIssueInstant(final Instant newIssueInstant) {
+        issueInstant = prepareForAssignment(issueInstant, newIssueInstant);
     }
 
     /** {@inheritDoc} */
@@ -111,7 +111,7 @@ public abstract class RequestAbstractTypeImpl extends AbstractSignableSAMLObject
 
     /** {@inheritDoc} */
     public void setDestination(final String newDestination) {
-        this.destination = prepareForAssignment(this.destination, newDestination);
+        destination = prepareForAssignment(destination, newDestination);
     }
 
     /** {@inheritDoc} */
@@ -121,7 +121,7 @@ public abstract class RequestAbstractTypeImpl extends AbstractSignableSAMLObject
 
     /** {@inheritDoc} */
     public void setConsent(final String newConsent) {
-        this.consent = prepareForAssignment(this.consent, newConsent);
+        consent = prepareForAssignment(consent, newConsent);
     }
 
     /** {@inheritDoc} */
@@ -131,17 +131,17 @@ public abstract class RequestAbstractTypeImpl extends AbstractSignableSAMLObject
 
     /** {@inheritDoc} */
     public void setIssuer(final Issuer newIssuer) {
-        this.issuer = prepareForAssignment(this.issuer, newIssuer);
+        issuer = prepareForAssignment(issuer, newIssuer);
     }
 
     /** {@inheritDoc} */
     public Extensions getExtensions() {
-        return this.extensions;
+        return extensions;
     }
 
     /** {@inheritDoc} */
     public void setExtensions(final Extensions newExtensions) {
-        this.extensions = prepareForAssignment(this.extensions, newExtensions);
+        extensions = prepareForAssignment(extensions, newExtensions);
     }
 
     /** {@inheritDoc} */
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeMarshaller.java
index b727ff5..9571c6c 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeMarshaller.java
@@ -52,7 +52,7 @@ public abstract class RequestAbstractTypeMarshaller extends AbstractSAMLObjectMa
         }
 
         if (req.getIssueInstant() != null) {
-            final String iiStr = SAMLConfigurationSupport.getSAMLDateFormatter().print(req.getIssueInstant());
+            final String iiStr = SAMLConfigurationSupport.getSAMLDateFormatter().format(req.getIssueInstant());
             domElement.setAttributeNS(null, RequestAbstractType.ISSUE_INSTANT_ATTRIB_NAME, iiStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeUnmarshaller.java
index 89640ba..9204505 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/RequestAbstractTypeUnmarshaller.java
@@ -21,8 +21,8 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -67,7 +67,7 @@ public abstract class RequestAbstractTypeUnmarshaller extends AbstractSAMLObject
                 attribute.getOwnerElement().setIdAttributeNode(attribute, true);
             } else if (attribute.getLocalName().equals(RequestAbstractType.ISSUE_INSTANT_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                req.setIssueInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                req.setIssueInstant(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(RequestAbstractType.DESTINATION_ATTRIB_NAME)) {
                 req.setDestination(attribute.getValue());
             } else if (attribute.getLocalName().equals(RequestAbstractType.CONSENT_ATTRIB_NAME)) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeImpl.java
index b22e51f..59383eb 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeImpl.java
@@ -21,11 +21,11 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.saml.common.AbstractSignableSAMLObject;
 import org.opensaml.saml.common.SAMLVersion;
@@ -49,7 +49,7 @@ public abstract class StatusResponseTypeImpl extends AbstractSignableSAMLObject
     private String inResponseTo;
 
     /** IssueInstant attribute. */
-    private DateTime issueInstant;
+    private Instant issueInstant;
 
     /** Destination attribute. */
     private String destination;
@@ -86,7 +86,7 @@ public abstract class StatusResponseTypeImpl extends AbstractSignableSAMLObject
 
     /** {@inheritDoc} */
     public void setVersion(final SAMLVersion newVersion) {
-        this.version = prepareForAssignment(this.version, newVersion);
+        version = prepareForAssignment(version, newVersion);
     }
     
     /** {@inheritDoc} */
@@ -112,13 +112,13 @@ public abstract class StatusResponseTypeImpl extends AbstractSignableSAMLObject
     }
 
     /** {@inheritDoc} */
-    public DateTime getIssueInstant() {
-        return this.issueInstant;
+    public Instant getIssueInstant() {
+        return issueInstant;
     }
 
     /** {@inheritDoc} */
-    public void setIssueInstant(final DateTime newIssueInstant) {
-        this.issueInstant = prepareForAssignment(this.issueInstant, newIssueInstant);
+    public void setIssueInstant(final Instant newIssueInstant) {
+        issueInstant = prepareForAssignment(issueInstant, newIssueInstant);
     }
 
     /** {@inheritDoc} */
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeMarshaller.java
index 21979de..0f9bf96 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeMarshaller.java
@@ -56,7 +56,7 @@ public abstract class StatusResponseTypeMarshaller extends AbstractSAMLObjectMar
         }
 
         if (sr.getIssueInstant() != null) {
-            final String iiStr = SAMLConfigurationSupport.getSAMLDateFormatter().print(sr.getIssueInstant());
+            final String iiStr = SAMLConfigurationSupport.getSAMLDateFormatter().format(sr.getIssueInstant());
             domElement.setAttributeNS(null, StatusResponseType.ISSUE_INSTANT_ATTRIB_NAME, iiStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeUnmarshaller.java
index 90a6ebb..024077d 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/StatusResponseTypeUnmarshaller.java
@@ -21,8 +21,8 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -72,7 +72,7 @@ public abstract class StatusResponseTypeUnmarshaller extends AbstractSAMLObjectU
                 sr.setInResponseTo(attribute.getValue());
             } else if (attribute.getLocalName().equals(StatusResponseType.ISSUE_INSTANT_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                sr.setIssueInstant(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                sr.setIssueInstant(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(StatusResponseType.DESTINATION_ATTRIB_NAME)) {
                 sr.setDestination(attribute.getValue());
             } else if (attribute.getLocalName().equals(StatusResponseType.CONSENT_ATTRIB_NAME)) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataImpl.java
index 7adb0bd..cd6715b 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataImpl.java
@@ -21,12 +21,12 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
+import java.time.Instant;
 import java.util.Collections;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.AttributeMap;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
@@ -39,10 +39,10 @@ import org.opensaml.saml.saml2.core.SubjectConfirmationData;
 public class SubjectConfirmationDataImpl extends AbstractSAMLObject implements SubjectConfirmationData {
 
     /** NotBefore of the Confirmation Data. */
-    private DateTime notBefore;
+    private Instant notBefore;
 
     /** NotOnOrAfter of the Confirmation Data. */
-    private DateTime notOnOrAfter;
+    private Instant notOnOrAfter;
 
     /** Recipient of the Confirmation Data. */
     private String recipient;
@@ -74,22 +74,22 @@ public class SubjectConfirmationDataImpl extends AbstractSAMLObject implements S
     }
 
     /** {@inheritDoc} */
-    public DateTime getNotBefore() {
+    public Instant getNotBefore() {
         return notBefore;
     }
 
     /** {@inheritDoc} */
-    public void setNotBefore(final DateTime newNotBefore) {
+    public void setNotBefore(final Instant newNotBefore) {
         this.notBefore = prepareForAssignment(this.notBefore, newNotBefore);
     }
 
     /** {@inheritDoc} */
-    public DateTime getNotOnOrAfter() {
+    public Instant getNotOnOrAfter() {
         return notOnOrAfter;
     }
 
     /** {@inheritDoc} */
-    public void setNotOnOrAfter(final DateTime newNotOnOrAfter) {
+    public void setNotOnOrAfter(final Instant newNotOnOrAfter) {
         this.notOnOrAfter = prepareForAssignment(this.notOnOrAfter, newNotOnOrAfter);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataMarshaller.java
index 4ded986..79979f0 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataMarshaller.java
@@ -39,13 +39,14 @@ public class SubjectConfirmationDataMarshaller extends AbstractSAMLObjectMarshal
         final SubjectConfirmationData subjectCD = (SubjectConfirmationData) samlObject;
 
         if (subjectCD.getNotBefore() != null) {
-            final String notBeforeStr = SAMLConfigurationSupport.getSAMLDateFormatter().print(subjectCD.getNotBefore());
+            final String notBeforeStr =
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(subjectCD.getNotBefore());
             domElement.setAttributeNS(null, SubjectConfirmationData.NOT_BEFORE_ATTRIB_NAME, notBeforeStr);
         }
 
         if (subjectCD.getNotOnOrAfter() != null) {
             final String notOnOrAfterStr =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(subjectCD.getNotOnOrAfter());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(subjectCD.getNotOnOrAfter());
             domElement.setAttributeNS(null, SubjectConfirmationData.NOT_ON_OR_AFTER_ATTRIB_NAME, notOnOrAfterStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataUnmarshaller.java
index 11db9b6..a19c730 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataUnmarshaller.java
@@ -21,8 +21,8 @@
 
 package org.opensaml.saml.saml2.core.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -53,10 +53,10 @@ public class SubjectConfirmationDataUnmarshaller extends AbstractSAMLObjectUnmar
         if (attribute.getNamespaceURI() == null) {
             if (attribute.getLocalName().equals(SubjectConfirmationData.NOT_BEFORE_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                subjectCD.setNotBefore(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                subjectCD.setNotBefore(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(SubjectConfirmationData.NOT_ON_OR_AFTER_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                subjectCD.setNotOnOrAfter(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                subjectCD.setNotOnOrAfter(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(SubjectConfirmationData.RECIPIENT_ATTRIB_NAME)) {
                 subjectCD.setRecipient(attribute.getValue());
             } else if (attribute.getLocalName().equals(SubjectConfirmationData.IN_RESPONSE_TO_ATTRIB_NAME)) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorImpl.java
index fa9d754..010f70c 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorImpl.java
@@ -21,11 +21,11 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.AttributeMap;
 import org.opensaml.core.xml.util.XMLObjectChildrenList;
@@ -47,7 +47,7 @@ public class AffiliationDescriptorImpl extends AbstractSignableSAMLObject implem
     private String id;
 
     /** validUntil attribute. */
-    private DateTime validUntil;
+    private Instant validUntil;
 
     /** cacheDurection attribute. */
     private Long cacheDuration;
@@ -115,19 +115,18 @@ public class AffiliationDescriptorImpl extends AbstractSignableSAMLObject implem
             return true;
         }
 
-        final DateTime now = new DateTime();
-        return now.isBefore(validUntil);
+        return Instant.now().isBefore(validUntil);
     }
 
     /** {@inheritDoc} */
     @Override
-    public DateTime getValidUntil() {
+    public Instant getValidUntil() {
         return validUntil;
     }
 
     /** {@inheritDoc} */
     @Override
-    public void setValidUntil(final DateTime theValidUntil) {
+    public void setValidUntil(final Instant theValidUntil) {
         this.validUntil = prepareForAssignment(this.validUntil, theValidUntil);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorMarshaller.java
index 11dac29..369729c 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorMarshaller.java
@@ -62,7 +62,7 @@ public class AffiliationDescriptorMarshaller extends AbstractSAMLObjectMarshalle
         if (descriptor.getValidUntil() != null) {
             log.debug("Writting validUntil attribute to AffiliationDescriptor DOM element");
             final String validUntilStr =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(descriptor.getValidUntil());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(descriptor.getValidUntil());
             domElement.setAttributeNS(null, TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME, validUntilStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorUnmarshaller.java
index 9ebb10b..137656f 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorUnmarshaller.java
@@ -19,8 +19,8 @@ package org.opensaml.saml.saml2.metadata.impl;
 
 import net.shibboleth.utilities.java.support.xml.DOMTypeSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -70,7 +70,7 @@ public class AffiliationDescriptorUnmarshaller extends AbstractSAMLObjectUnmarsh
                 attribute.getOwnerElement().setIdAttributeNode(attribute, true);
             } else if (attribute.getLocalName().equals(TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                descriptor.setValidUntil(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                descriptor.setValidUntil(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(CacheableSAMLObject.CACHE_DURATION_ATTRIB_NAME)) {
                 descriptor.setCacheDuration(DOMTypeSupport.durationToLong(attribute.getValue()));
             } else {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorImpl.java
index d288552..968c73b 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorImpl.java
@@ -17,11 +17,11 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
 import org.opensaml.saml.common.AbstractSignableSAMLObject;
@@ -42,7 +42,7 @@ public class EntitiesDescriptorImpl extends AbstractSignableSAMLObject implement
     private String id;
 
     /** validUntil attribute. */
-    private DateTime validUntil;
+    private Instant validUntil;
 
     /** cacheDurection attribute. */
     private Long cacheDuration;
@@ -94,17 +94,16 @@ public class EntitiesDescriptorImpl extends AbstractSignableSAMLObject implement
             return true;
         }
         
-        final DateTime now = new DateTime();
-        return now.isBefore(validUntil);
+        return Instant.now().isBefore(validUntil);
     }
 
     /** {@inheritDoc} */
-    public DateTime getValidUntil() {
+    public Instant getValidUntil() {
         return validUntil;
     }
 
     /** {@inheritDoc} */
-    public void setValidUntil(final DateTime newValidUntil) {
+    public void setValidUntil(final Instant newValidUntil) {
         validUntil = prepareForAssignment(validUntil, newValidUntil);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorMarshaller.java
index 732cc70..3b3ef45 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorMarshaller.java
@@ -53,7 +53,7 @@ public class EntitiesDescriptorMarshaller extends AbstractSAMLObjectMarshaller {
         if (entitiesDescriptor.getValidUntil() != null) {
             log.debug("Writting validUntil attribute to EntitiesDescriptor DOM element");
             final String validUntilStr =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(entitiesDescriptor.getValidUntil());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(entitiesDescriptor.getValidUntil());
             domElement.setAttributeNS(null, TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME, validUntilStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorUnmarshaller.java
index 8c001ce..2e752ce 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorUnmarshaller.java
@@ -19,8 +19,8 @@ package org.opensaml.saml.saml2.metadata.impl;
 
 import net.shibboleth.utilities.java.support.xml.DOMTypeSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -67,7 +67,7 @@ public class EntitiesDescriptorUnmarshaller extends AbstractSAMLObjectUnmarshall
                 attribute.getOwnerElement().setIdAttributeNode(attribute, true);
             } else if (attribute.getLocalName().equals(TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                entitiesDescriptor.setValidUntil(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                entitiesDescriptor.setValidUntil(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(CacheableSAMLObject.CACHE_DURATION_ATTRIB_NAME)) {
                 entitiesDescriptor.setCacheDuration(Long.valueOf(DOMTypeSupport.durationToLong(attribute.getValue())));
             } else if (attribute.getLocalName().equals(EntitiesDescriptor.NAME_ATTRIB_NAME)) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorImpl.java
index 6e21b14..5f0ab66 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorImpl.java
@@ -17,13 +17,13 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.AttributeMap;
 import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList;
@@ -54,7 +54,7 @@ public class EntityDescriptorImpl extends AbstractSignableSAMLObject implements
     private String id;
 
     /** validUntil attribute. */
-    private DateTime validUntil;
+    private Instant validUntil;
 
     /** cacheDurection attribute. */
     private Long cacheDuration;
@@ -127,17 +127,16 @@ public class EntityDescriptorImpl extends AbstractSignableSAMLObject implements
             return true;
         }
 
-        final DateTime now = new DateTime();
-        return now.isBefore(validUntil);
+        return Instant.now().isBefore(validUntil);
     }
 
     /** {@inheritDoc} */
-    public DateTime getValidUntil() {
+    public Instant getValidUntil() {
         return validUntil;
     }
 
     /** {@inheritDoc} */
-    public void setValidUntil(final DateTime newValidUntil) {
+    public void setValidUntil(final Instant newValidUntil) {
         validUntil = prepareForAssignment(validUntil, newValidUntil);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorMarshaller.java
index 30ddb5d..75bcd8c 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorMarshaller.java
@@ -56,7 +56,7 @@ public class EntityDescriptorMarshaller extends AbstractSAMLObjectMarshaller {
         if (entityDescriptor.getValidUntil() != null) {
             log.debug("Writting validUntil attribute to EntityDescriptor DOM element");
             final String validUntilStr =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(entityDescriptor.getValidUntil());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(entityDescriptor.getValidUntil());
             domElement.setAttributeNS(null, TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME, validUntilStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorUnmarshaller.java
index 76ce9eb..5417205 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorUnmarshaller.java
@@ -19,8 +19,8 @@ package org.opensaml.saml.saml2.metadata.impl;
 
 import net.shibboleth.utilities.java.support.xml.DOMTypeSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -79,7 +79,7 @@ public class EntityDescriptorUnmarshaller extends AbstractSAMLObjectUnmarshaller
                 attribute.getOwnerElement().setIdAttributeNode(attribute, true);
             } else if (attribute.getLocalName().equals(TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                entityDescriptor.setValidUntil(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                entityDescriptor.setValidUntil(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(CacheableSAMLObject.CACHE_DURATION_ATTRIB_NAME)) {
                 entityDescriptor.setCacheDuration(DOMTypeSupport.durationToLong(attribute.getValue()));
             } else {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorImpl.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorImpl.java
index 223da4e..33fa9fd 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorImpl.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorImpl.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -25,7 +26,6 @@ import java.util.List;
 import net.shibboleth.utilities.java.support.collection.LazyList;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.util.AttributeMap;
 import org.opensaml.core.xml.util.XMLObjectChildrenList;
@@ -43,7 +43,7 @@ public abstract class RoleDescriptorImpl extends AbstractSignableSAMLObject impl
     private String id;
 
     /** validUntil attribute. */
-    private DateTime validUntil;
+    private Instant validUntil;
 
     /** cacheDurection attribute. */
     private Long cacheDuration;
@@ -106,19 +106,18 @@ public abstract class RoleDescriptorImpl extends AbstractSignableSAMLObject impl
             return true;
         }
         
-        final DateTime now = new DateTime();
-        return now.isBefore(validUntil);
+        return Instant.now().isBefore(validUntil);
     }
 
     /** {@inheritDoc} */
     @Override
-    public DateTime getValidUntil() {
+    public Instant getValidUntil() {
         return validUntil;
     }
 
     /** {@inheritDoc} */
     @Override
-    public void setValidUntil(final DateTime dt) {
+    public void setValidUntil(final Instant dt) {
         validUntil = prepareForAssignment(validUntil, dt);
     }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorMarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorMarshaller.java
index 5e9238d..5a0aa15 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorMarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorMarshaller.java
@@ -56,7 +56,7 @@ public abstract class RoleDescriptorMarshaller extends AbstractSAMLObjectMarshal
         if (roleDescriptor.getValidUntil() != null) {
             log.trace("Writting validUntil attribute to RoleDescriptor DOM element");
             final String validUntilStr =
-                    SAMLConfigurationSupport.getSAMLDateFormatter().print(roleDescriptor.getValidUntil());
+                    SAMLConfigurationSupport.getSAMLDateFormatter().format(roleDescriptor.getValidUntil());
             domElement.setAttributeNS(null, TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME, validUntilStr);
         }
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorUnmarshaller.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorUnmarshaller.java
index b8469fe..27418d7 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorUnmarshaller.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/metadata/impl/RoleDescriptorUnmarshaller.java
@@ -17,12 +17,11 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.StringTokenizer;
 
 import net.shibboleth.utilities.java.support.xml.DOMTypeSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.AbstractSAMLObjectUnmarshaller;
@@ -73,7 +72,7 @@ public abstract class RoleDescriptorUnmarshaller extends AbstractSAMLObjectUnmar
                 attribute.getOwnerElement().setIdAttributeNode(attribute, true);
             } else if (attribute.getLocalName().equals(TimeBoundSAMLObject.VALID_UNTIL_ATTRIB_NAME)
                     && !Strings.isNullOrEmpty(attribute.getValue())) {
-                roleDescriptor.setValidUntil(new DateTime(attribute.getValue(), ISOChronology.getInstanceUTC()));
+                roleDescriptor.setValidUntil(Instant.parse(attribute.getValue()));
             } else if (attribute.getLocalName().equals(CacheableSAMLObject.CACHE_DURATION_ATTRIB_NAME)) {
                 roleDescriptor.setCacheDuration(DOMTypeSupport.durationToLong(attribute.getValue()));
             } else if (attribute.getLocalName().equals(RoleDescriptor.PROTOCOL_ENUMERATION_ATTRIB_NAME)) {
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AbstractResponseShellAction.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AbstractResponseShellAction.java
index 9436d28..09bb506 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AbstractResponseShellAction.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AbstractResponseShellAction.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.saml2.profile.impl;
 
+import java.time.Instant;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -28,8 +29,6 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
 import net.shibboleth.utilities.java.support.security.SecureRandomIdentifierGenerationStrategy;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectBuilderFactory;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.messaging.context.MessageContext;
@@ -176,7 +175,7 @@ public abstract class AbstractResponseShellAction<MessageType extends StatusResp
         final MessageType response = responseBuilder.buildObject();
 
         response.setID(idGenerator.generateIdentifier());
-        response.setIssueInstant(new DateTime(ISOChronology.getInstanceUTC()));
+        response.setIssueInstant(Instant.now());
         response.setStatus(status);
         response.setVersion(SAMLVersion.VERSION_20);
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddStatusResponseShell.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddStatusResponseShell.java
index e7e874d..46abd2c 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddStatusResponseShell.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddStatusResponseShell.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.saml.saml2.profile.impl;
 
+import java.time.Instant;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -30,8 +31,6 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
 import net.shibboleth.utilities.java.support.security.SecureRandomIdentifierGenerationStrategy;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectBuilderFactory;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.messaging.context.MessageContext;
@@ -209,7 +208,7 @@ public class AddStatusResponseShell extends AbstractProfileAction {
         final StatusResponseType response = (StatusResponseType) object;
         
         response.setID(idGenerator.generateIdentifier());
-        response.setIssueInstant(new DateTime(ISOChronology.getInstanceUTC()));
+        response.setIssueInstant(Instant.now());
         response.setStatus(status);
         response.setVersion(SAMLVersion.VERSION_20);
 
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddSubjectConfirmationToSubjects.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddSubjectConfirmationToSubjects.java
index 54c5df5..f47daff 100644
--- a/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddSubjectConfirmationToSubjects.java
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/saml2/profile/impl/AddSubjectConfirmationToSubjects.java
@@ -18,12 +18,12 @@
 package org.opensaml.saml.saml2.profile.impl;
 
 import java.net.URI;
+import java.time.Instant;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.opensaml.profile.action.AbstractProfileAction;
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
@@ -311,7 +311,7 @@ public class AddSubjectConfirmationToSubjects extends AbstractProfileAction {
                 ? lifetimeLookupStrategy.apply(profileRequestContext) : null;
         if (lifetime != null) {
             confirmationData = confirmationData != null ? confirmationData : confirmationDataBuilder.buildObject();
-            confirmationData.setNotOnOrAfter(new DateTime().plus(lifetime));
+            confirmationData.setNotOnOrAfter(Instant.now().plusMillis(lifetime));
         }
         
         if (confirmationData != null) {
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandlerTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandlerTest.java
index d77b38f..96cb395 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandlerTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/MessageLifetimeSecurityHandlerTest.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.common.binding.security.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.handler.MessageHandlerException;
@@ -40,11 +40,11 @@ public class MessageLifetimeSecurityHandlerTest extends XMLObjectBaseTestCase {
     private long clockSkew;
     private long messageLifetime;
     
-    private DateTime now;
+    private Instant now;
 
     @BeforeMethod
     protected void setUp() throws Exception {
-        now = new DateTime(DateTimeZone.UTC);
+        now = Instant.now();
         clockSkew = 60*5*1000;
         messageLifetime = 60*10*1000;
         
@@ -73,7 +73,7 @@ public class MessageLifetimeSecurityHandlerTest extends XMLObjectBaseTestCase {
      */
     @Test(expectedExceptions=MessageHandlerException.class)
     public void testInvalidIssuedInFuture() throws MessageHandlerException {
-        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.plus(clockSkew + 5000));
+        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.plusMillis(clockSkew + 5000));
         handler.invoke(messageContext);
     }
     
@@ -83,7 +83,7 @@ public class MessageLifetimeSecurityHandlerTest extends XMLObjectBaseTestCase {
      */
     @Test
     public void testValidIssuedInFutureWithinClockSkew() throws MessageHandlerException {
-        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.plus(clockSkew - 5000));
+        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.plusMillis(clockSkew - 5000));
         handler.invoke(messageContext);
     }
     
@@ -93,7 +93,7 @@ public class MessageLifetimeSecurityHandlerTest extends XMLObjectBaseTestCase {
      */
     @Test(expectedExceptions=MessageHandlerException.class)
     public void testInvalidExpired() throws MessageHandlerException {
-        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.minus(messageLifetime + (clockSkew + 5000)));
+        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.minusMillis(messageLifetime + (clockSkew + 5000)));
         handler.invoke(messageContext);
     }
     
@@ -103,7 +103,7 @@ public class MessageLifetimeSecurityHandlerTest extends XMLObjectBaseTestCase {
      */
     @Test
     public void testValidExpiredWithinClockSkew() throws MessageHandlerException {
-        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.minus(messageLifetime + (clockSkew - 5000)));
+        messageContext.getSubcontext(SAMLMessageInfoContext.class, true).setMessageIssueInstant(now.minusMillis(messageLifetime + (clockSkew - 5000)));
         handler.invoke(messageContext);
     }
  
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/SAMLOutboundProtocolMessageSigningHandlerTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/SAMLOutboundProtocolMessageSigningHandlerTest.java
index 8f7f517..46b8ece 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/SAMLOutboundProtocolMessageSigningHandlerTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/binding/security/impl/SAMLOutboundProtocolMessageSigningHandlerTest.java
@@ -20,10 +20,10 @@ package org.opensaml.saml.common.binding.security.impl;
 import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
+import java.time.Instant;
 
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.handler.MessageHandlerException;
@@ -74,7 +74,7 @@ public class SAMLOutboundProtocolMessageSigningHandlerTest extends XMLObjectBase
     public void testSAML2Response() throws MessageHandlerException {
         Response response = buildXMLObject(Response.DEFAULT_ELEMENT_NAME);
         response.setID("abc123");
-        response.setIssueInstant(new DateTime());
+        response.setIssueInstant(Instant.now());
         
         Issuer issuer = buildXMLObject(Issuer.DEFAULT_ELEMENT_NAME);
         issuer.setValue("http://idp.example.org");
@@ -97,7 +97,7 @@ public class SAMLOutboundProtocolMessageSigningHandlerTest extends XMLObjectBase
     public void testSAML2ErrorResponse() throws MessageHandlerException {
         Response response = buildXMLObject(Response.DEFAULT_ELEMENT_NAME);
         response.setID("abc123");
-        response.setIssueInstant(new DateTime());
+        response.setIssueInstant(Instant.now());
         
         Issuer issuer = buildXMLObject(Issuer.DEFAULT_ELEMENT_NAME);
         issuer.setValue("http://idp.example.org");
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContextTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContextTest.java
index 5cd243a..4fc0973 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContextTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/messaging/context/SAMLMessageInfoContextTest.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.common.messaging.context;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.messaging.context.TestContext;
@@ -39,12 +39,12 @@ public class SAMLMessageInfoContextTest extends XMLObjectBaseTestCase {
     
     private String id;
     
-    private DateTime issueInstant;
+    private Instant issueInstant;
     
     @BeforeClass
     public void setUp() {
         id = "abc123";
-        issueInstant = new DateTime(DateTimeZone.UTC);
+        issueInstant = Instant.now();
     }
     
     @Test
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertionsTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertionsTest.java
index 980741f..380236a 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertionsTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/profile/impl/AddNotOnOrAfterConditionToAssertionsTest.java
@@ -90,7 +90,7 @@ public class AddNotOnOrAfterConditionToAssertionsTest  extends OpenSAMLInitBaseT
         Assert.assertNotNull(assertion.getConditions());
         Assert.assertNotNull(assertion.getConditions().getNotOnOrAfter());
         Assert.assertEquals(
-                assertion.getConditions().getNotOnOrAfter().minus(response.getIssueInstant().getMillis()).getMillis(),
+                assertion.getConditions().getNotOnOrAfter().minusMillis(response.getIssueInstant().toEpochMilli()).toEpochMilli(),
                 5 * 60 * 1000);
     }
 
@@ -121,7 +121,7 @@ public class AddNotOnOrAfterConditionToAssertionsTest  extends OpenSAMLInitBaseT
         Assert.assertSame(assertion.getConditions(), conditions);
         Assert.assertNotNull(assertion.getConditions().getNotOnOrAfter());
         Assert.assertEquals(
-                assertion.getConditions().getNotOnOrAfter().minus(response.getIssueInstant().getMillis()).getMillis(),
+                assertion.getConditions().getNotOnOrAfter().minusMillis(response.getIssueInstant().toEpochMilli()).toEpochMilli(),
                 10 * 60 * 1000);
     }
 
@@ -147,7 +147,7 @@ public class AddNotOnOrAfterConditionToAssertionsTest  extends OpenSAMLInitBaseT
             Assert.assertNotNull(assertion.getConditions());
             Assert.assertNotNull(assertion.getConditions().getNotOnOrAfter());
             Assert.assertEquals(
-                    assertion.getConditions().getNotOnOrAfter().minus(response.getIssueInstant().getMillis()).getMillis(),
+                    assertion.getConditions().getNotOnOrAfter().minusMillis(response.getIssueInstant().toEpochMilli()).toEpochMilli(),
                     3 * 60 * 1000);
         }
     }
@@ -172,7 +172,7 @@ public class AddNotOnOrAfterConditionToAssertionsTest  extends OpenSAMLInitBaseT
         Assert.assertNotNull(assertion.getConditions());
         Assert.assertNotNull(assertion.getConditions().getNotOnOrAfter());
         Assert.assertEquals(
-                assertion.getConditions().getNotOnOrAfter().minus(response.getIssueInstant().getMillis()).getMillis(),
+                assertion.getConditions().getNotOnOrAfter().minusMillis(response.getIssueInstant().toEpochMilli()).toEpochMilli(),
                 5 * 60 * 1000);
     }
     
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateTest.java
index c86186e..2fce851 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2delrestrict/impl/DelegateTest.java
@@ -20,8 +20,9 @@ package org.opensaml.saml.ext.saml2delrestrict.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.ext.saml2delrestrict.Delegate;
 import org.opensaml.saml.saml2.core.NameID;
@@ -31,7 +32,7 @@ import org.opensaml.saml.saml2.core.NameID;
  */
 public class DelegateTest extends XMLObjectProviderBaseTestCase {
 
-    private DateTime expectedDelegationInstant;
+    private Instant expectedDelegationInstant;
     
     private String expectedConfirmationMethod;
     
@@ -45,7 +46,7 @@ public class DelegateTest extends XMLObjectProviderBaseTestCase {
 
     @BeforeMethod
     protected void setUp() throws Exception {
-        expectedDelegationInstant = new DateTime(1984, 8, 26, 10, 01, 30, 43, ISOChronology.getInstanceUTC());
+        expectedDelegationInstant = Instant.parse("1984-08-26T10:01:30.043Z");
         expectedConfirmationMethod = "urn:oasis:names:tc:SAML:2.0:cm:bearer";
     }
 
@@ -64,7 +65,7 @@ public class DelegateTest extends XMLObjectProviderBaseTestCase {
         
         Assert.assertNotNull(delegate);
 
-        DateTime instant = delegate.getDelegationInstant();
+        Instant instant = delegate.getDelegationInstant();
         Assert.assertEquals(instant, expectedDelegationInstant, "DelegationInstant was unexpected value");
 
         String cm = delegate.getConfirmationMethod();
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesTest.java
index 5ef2c98..5e9f5b5 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdattr/impl/EntityAttributesTest.java
@@ -19,8 +19,9 @@ package org.opensaml.saml.ext.saml2mdattr.impl;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
+
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.ext.saml2mdattr.EntityAttributes;
 import org.opensaml.saml.saml2.core.Assertion;
@@ -66,9 +67,9 @@ public class EntityAttributesTest extends XMLObjectProviderBaseTestCase {
     @Test
     public void testChildElementsMarshall() {
         Assertion assertion1 = (Assertion) buildXMLObject(Assertion.DEFAULT_ELEMENT_NAME);
-        assertion1.setIssueInstant(new DateTime(1984, 8, 26, 10, 01, 30, 0, DateTimeZone.UTC));
+        assertion1.setIssueInstant(Instant.parse("1984-08-26T10:01:30Z"));
         Assertion assertion2 = (Assertion) buildXMLObject(Assertion.DEFAULT_ELEMENT_NAME);
-        assertion2.setIssueInstant(new DateTime(1984, 8, 26, 10, 01, 30, 0, DateTimeZone.UTC));
+        assertion2.setIssueInstant(Instant.parse("1984-08-26T10:01:30Z"));
         
         Attribute attrib1 = (Attribute) buildXMLObject(Attribute.DEFAULT_ELEMENT_NAME);
         attrib1.setName("attrib1");
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoTest.java
index 53dbb01..0712288 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationInfoTest.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.ext.saml2mdrpi.PublicationInfo;
 import org.opensaml.saml.ext.saml2mdrpi.UsagePolicy;
@@ -29,7 +29,7 @@ public class PublicationInfoTest extends XMLObjectProviderBaseTestCase {
 
     private static String expectedPublisher = "publisher";
     private static String expectedPublicationId = "Ident";
-    private static DateTime expectedCreationInstant = new DateTime(2010, 8, 11, 14, 59, 1, 2, ISOChronology.getInstanceUTC());
+    private static Instant expectedCreationInstant = Instant.parse("2010-08-11T14:59:01.002Z");
 
     private static String[] langs = {"en", "fr",};
     private static String[] uris = {"https://www.aai.dfn.de/en/join/","https://www.example.fr/fr/",};
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationTest.java
index e1ebd5c..89c9bcc 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/PublicationTest.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.ext.saml2mdrpi.Publication;
 import org.testng.Assert;
@@ -27,7 +27,7 @@ public class PublicationTest extends XMLObjectProviderBaseTestCase {
 
     private static String expectedPublisher = "publisher";
     private static String expectedPublicationId = "Ident";
-    private static DateTime expectedCreationInstant = new DateTime(2010, 8, 11, 14, 59, 1, 2, ISOChronology.getInstanceUTC());
+    private static Instant expectedCreationInstant = Instant.parse("2010-08-11T14:59:01.002Z");
 
     /**
      * Constructor.
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoTest.java
index c5ed7ff..c31bec3 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/ext/saml2mdrpi/impl/RegistrationInfoTest.java
@@ -17,8 +17,8 @@
 
 package org.opensaml.saml.ext.saml2mdrpi.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.ext.saml2mdrpi.RegistrationInfo;
 import org.opensaml.saml.ext.saml2mdrpi.RegistrationPolicy;
@@ -30,7 +30,7 @@ public class RegistrationInfoTest extends XMLObjectProviderBaseTestCase {
 
     private static String expectedAuthority = "https://www.aai.dfn.de";
 
-    private static DateTime expectedRegistrationInstant = new DateTime(2010, 8, 11, 14, 59, 1, 2, ISOChronology.getInstanceUTC());
+    private static Instant expectedRegistrationInstant = Instant.parse("2010-08-11T14:59:01.002Z");
 
     private static String[] langs = {"en", "de",};
     private static String[] uris = {"grhttps://www.aai.dfn.de/en/join/","https://www.aai.dfn.de/teilnahme/",};
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilTest.java
index 93b87f4..b736579 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/filter/impl/RequiredValidUntilTest.java
@@ -19,11 +19,10 @@ package org.opensaml.saml.metadata.resolver.filter.impl;
 
 import java.io.File;
 import java.net.URL;
+import java.time.Instant;
 
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.saml.common.SAMLObjectBuilder;
@@ -104,7 +103,7 @@ public class RequiredValidUntilTest extends XMLObjectBaseTestCase {
         SAMLObjectBuilder<EntitiesDescriptor> entitiesDescriptorBuilder = 
                 (SAMLObjectBuilder<EntitiesDescriptor>) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(EntitiesDescriptor.TYPE_NAME);
         EntitiesDescriptor descriptor = entitiesDescriptorBuilder.buildObject();
-        descriptor.setValidUntil(new DateTime(ISOChronology.getInstanceUTC()).minus(10000));
+        descriptor.setValidUntil(Instant.now().minusMillis(10000));
 
         RequiredValidUntilFilter filter = new RequiredValidUntilFilter(-1);
         filter.filter(descriptor);
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolverTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolverTest.java
index 5ceedac..b6b25ec 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolverTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/metadata/resolver/impl/FileBackedHTTPMetadataResolverTest.java
@@ -23,9 +23,8 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.Instant;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.saml.saml2.metadata.EntityDescriptor;
@@ -220,8 +219,8 @@ public class FileBackedHTTPMetadataResolverTest extends XMLObjectBaseTestCase {
         
         Assert.assertTrue(metadataProvider.isInitializedFromBackupFile());
         
-        DateTime initRefresh = metadataProvider.getLastRefresh();
-        DateTime initUpdate = metadataProvider.getLastUpdate();
+        Instant initRefresh = metadataProvider.getLastRefresh();
+        Instant initUpdate = metadataProvider.getLastUpdate();
         
         Assert.assertNotNull(metadataProvider.resolveSingle(criteriaSet), "Metadata inited from backing file was null");
         
@@ -261,9 +260,9 @@ public class FileBackedHTTPMetadataResolverTest extends XMLObjectBaseTestCase {
         
         Assert.assertTrue(metadataProvider.isInitializedFromBackupFile());
         
-        DateTime postInit = new DateTime(ISOChronology.getInstanceUTC());
-        DateTime initRefresh = metadataProvider.getLastRefresh();
-        DateTime initUpdate = metadataProvider.getLastUpdate();
+        Instant postInit = Instant.now();
+        Instant initRefresh = metadataProvider.getLastRefresh();
+        Instant initUpdate = metadataProvider.getLastUpdate();
         
         // Metadata was expired, so have no live metadata at this point
         Assert.assertNull(initUpdate);
@@ -273,7 +272,7 @@ public class FileBackedHTTPMetadataResolverTest extends XMLObjectBaseTestCase {
         Thread.sleep(metadataProvider.getBackupFileInitNextRefreshDelay() + 5000);
         
         Assert.assertTrue(initRefresh.isBefore(metadataProvider.getLastRefresh()));
-        DateTime refreshUpdate = metadataProvider.getLastUpdate();
+        Instant refreshUpdate = metadataProvider.getLastUpdate();
         Assert.assertNotNull(refreshUpdate);
         Assert.assertTrue(refreshUpdate.isAfter(postInit));
         
@@ -307,9 +306,9 @@ public class FileBackedHTTPMetadataResolverTest extends XMLObjectBaseTestCase {
         
         Assert.assertTrue(metadataProvider.isInitializedFromBackupFile());
         
-        DateTime postInit = new DateTime(ISOChronology.getInstanceUTC());
-        DateTime initRefresh = metadataProvider.getLastRefresh();
-        DateTime initUpdate = metadataProvider.getLastUpdate();
+        Instant postInit = Instant.now();
+        Instant initRefresh = metadataProvider.getLastRefresh();
+        Instant initUpdate = metadataProvider.getLastUpdate();
         
         // Metadata was fundamentally not able to be processed, so have no live metadata at this point
         Assert.assertNull(initUpdate);
@@ -319,7 +318,7 @@ public class FileBackedHTTPMetadataResolverTest extends XMLObjectBaseTestCase {
         Thread.sleep(metadataProvider.getBackupFileInitNextRefreshDelay() + 5000);
         
         Assert.assertTrue(initRefresh.isBefore(metadataProvider.getLastRefresh()));
-        DateTime refreshUpdate = metadataProvider.getLastUpdate();
+        Instant refreshUpdate = metadataProvider.getLastUpdate();
         Assert.assertNotNull(refreshUpdate);
         Assert.assertTrue(refreshUpdate.isAfter(postInit));
         
@@ -350,8 +349,8 @@ public class FileBackedHTTPMetadataResolverTest extends XMLObjectBaseTestCase {
         
         Assert.assertTrue(metadataProvider.isInitializedFromBackupFile());
         
-        DateTime initRefresh = metadataProvider.getLastRefresh();
-        DateTime initUpdate = metadataProvider.getLastUpdate();
+        Instant initRefresh = metadataProvider.getLastRefresh();
+        Instant initUpdate = metadataProvider.getLastUpdate();
         
         Assert.assertNotNull(metadataProvider.resolveSingle(criteriaSet), "Metadata retrieved from backing file was null");
         
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java
index c5f309e..b22109b 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPPostEncoderTest.java
@@ -18,11 +18,11 @@
 package org.opensaml.saml.saml1.binding.encoding.impl;
 
 import java.io.ByteArrayInputStream;
+import java.time.Instant;
 import java.util.List;
 
 import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.runtime.RuntimeConstants;
-import org.joda.time.DateTime;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.DocumentType;
@@ -74,7 +74,7 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
                 .getBuilder(Response.DEFAULT_ELEMENT_NAME);
         Response samlMessage = requestBuilder.buildObject();
         samlMessage.setID("foo");
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setVersion(SAMLVersion.VERSION_11);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPSOAP11EncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPSOAP11EncoderTest.java
index 33d323d..aaf88a1 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPSOAP11EncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/binding/encoding/impl/HTTPSOAP11EncoderTest.java
@@ -18,8 +18,8 @@
 package org.opensaml.saml.saml1.binding.encoding.impl;
 
 import java.io.ByteArrayInputStream;
+import java.time.Instant;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.core.xml.util.XMLObjectSupport;
@@ -51,7 +51,7 @@ public class HTTPSOAP11EncoderTest extends XMLObjectBaseTestCase {
                 .getBuilder(Request.DEFAULT_ELEMENT_NAME);
         Request request = requestBuilder.buildObject();
         request.setID("foo");
-        request.setIssueInstant(new DateTime(0));
+        request.setIssueInstant(Instant.ofEpochMilli(0));
         request.setVersion(SAMLVersion.VERSION_11);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AssertionTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AssertionTest.java
index beeeec0..421212f 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AssertionTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AssertionTest.java
@@ -23,10 +23,11 @@ package org.opensaml.saml.saml1.core.impl;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.saml1.core.Advice;
@@ -51,7 +52,7 @@ public class AssertionTest extends XMLObjectProviderBaseTestCase {
 
     private final String expectedIssuer;
 
-    private final DateTime expectedIssueInstant;
+    private final Instant expectedIssueInstant;
 
     private final String expectedID;
     
@@ -62,10 +63,7 @@ public class AssertionTest extends XMLObjectProviderBaseTestCase {
         expectedID = "ident";
         expectedMinorVersion = 1;
         expectedIssuer = "issuer";
-        //
-        // IssueInstant="1970-01-02T01:01:02.100Z"
-        //
-        expectedIssueInstant = new DateTime(1970, 1, 2, 1, 1, 2, 100, ISOChronology.getInstanceUTC());
+        expectedIssueInstant = Instant.parse("1970-01-02T01:01:02.100Z");
 
         singleElementFile = "/org/opensaml/saml/saml1/impl/singleAssertion.xml";
         singleElementOptionalAttributesFile = "/org/opensaml/saml/saml1/impl/singleAssertionAttributes.xml";
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementTest.java
index 862ac56..12a6a4b 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/AuthenticationStatementTest.java
@@ -23,10 +23,11 @@ package org.opensaml.saml.saml1.core.impl;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml1.core.AuthenticationStatement;
@@ -46,7 +47,7 @@ public class AuthenticationStatementTest extends XMLObjectProviderBaseTestCase {
     private String expectedAuthenticationMethod;
 
     /** Expected value of AuthenticationInstant */
-    private DateTime expectedAuthenticationInstant;
+    private Instant expectedAuthenticationInstant;
 
     /**
      * Constructor
@@ -54,10 +55,7 @@ public class AuthenticationStatementTest extends XMLObjectProviderBaseTestCase {
     public AuthenticationStatementTest() {
         super();
         expectedAuthenticationMethod = "trustme";
-        //
-        // AuthenticationInstant="1970-01-02T01:01:02.123Z"
-        //
-        expectedAuthenticationInstant = new DateTime(1970, 1, 2, 1, 1, 2, 123, ISOChronology.getInstanceUTC());
+        expectedAuthenticationInstant = Instant.parse("1970-01-02T01:01:02.123Z");
 
         singleElementFile = "/org/opensaml/saml/saml1/impl/singleAuthenticationStatement.xml";
         singleElementOptionalAttributesFile = "/org/opensaml/saml/saml1/impl/singleAuthenticationStatementAttributes.xml";
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ConditionsTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ConditionsTest.java
index 5bd95f8..7f1a993 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ConditionsTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ConditionsTest.java
@@ -23,10 +23,11 @@ package org.opensaml.saml.saml1.core.impl;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml1.core.AudienceRestrictionCondition;
@@ -44,12 +45,12 @@ public class ConditionsTest extends XMLObjectProviderBaseTestCase {
     /**
      * Representation of NotBefore in test file.
      */
-    private final DateTime expectedNotBeforeDate;
+    private final Instant expectedNotBeforeDate;
 
     /**
      * Representation of NotOnOrAfter in test file.
      */
-    private final DateTime expectedNotOnOfAfter;
+    private final Instant expectedNotOnOfAfter;
 
     /**
      * Constructor
@@ -59,14 +60,8 @@ public class ConditionsTest extends XMLObjectProviderBaseTestCase {
         singleElementFile = "/org/opensaml/saml/saml1/impl/singleConditions.xml";
         singleElementOptionalAttributesFile = "/org/opensaml/saml/saml1/impl/singleConditionsAttributes.xml";
         childElementsFile = "/org/opensaml/saml/saml1/impl/ConditionsWithChildren.xml";
-        //
-        // NotBefore="1970-01-01T01:00:00.123Z"
-        //
-        expectedNotBeforeDate = new DateTime(1970, 1, 01, 01, 00, 00, 123, ISOChronology.getInstanceUTC());
-        //
-        // NotOnOrAfter="1970-01-01T00:00:01.000Z"
-        //
-        expectedNotOnOfAfter = new DateTime(1970, 1, 01, 00, 00, 01, 0, ISOChronology.getInstanceUTC());
+        expectedNotBeforeDate = Instant.parse("1970-01-01T01:00:00.123Z");
+        expectedNotOnOfAfter = Instant.parse("1970-01-01T00:00:01Z");
         
         qname = new QName(SAMLConstants.SAML1_NS, Conditions.DEFAULT_ELEMENT_LOCAL_NAME, SAMLConstants.SAML1_PREFIX);
     }
@@ -78,7 +73,7 @@ public class ConditionsTest extends XMLObjectProviderBaseTestCase {
 
         conditions = (Conditions) unmarshallElement(singleElementFile);
 
-        DateTime date = conditions.getNotBefore();
+        Instant date = conditions.getNotBefore();
         Assert.assertNull(date, "NotBefore attribute has a value of " + date + ", expected no value");
 
         date = conditions.getNotOnOrAfter();
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/RequestTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/RequestTest.java
index ff2f152..8d8f351 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/RequestTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/RequestTest.java
@@ -22,12 +22,13 @@ package org.opensaml.saml.saml1.core.impl;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
 import net.shibboleth.utilities.java.support.xml.XMLParserException;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.saml1.core.AssertionArtifact;
@@ -47,7 +48,7 @@ public class RequestTest extends XMLObjectProviderBaseTestCase {
 
     private final String expectedID;
     
-    private final DateTime expectedIssueInstant;
+    private final Instant expectedIssueInstant;
 
     private final int expectedMinorVersion;
     
@@ -55,7 +56,7 @@ public class RequestTest extends XMLObjectProviderBaseTestCase {
         expectedID = "ident";
         singleElementFile = "/org/opensaml/saml/saml1/impl/singleRequest.xml";
         singleElementOptionalAttributesFile = "/org/opensaml/saml/saml1/impl/singleRequestAttributes.xml";
-        expectedIssueInstant = new DateTime(1970, 1, 1, 0, 0, 0, 100, ISOChronology.getInstanceUTC());
+        expectedIssueInstant = Instant.parse("1970-01-01T00:00:00.100Z");
         expectedMinorVersion = 1;
         qname = Request.DEFAULT_ELEMENT_NAME;
     }
@@ -68,7 +69,7 @@ public class RequestTest extends XMLObjectProviderBaseTestCase {
         String id = request.getID();
         Assert.assertNull(id, "ID attribute has value " + id + "expected no value");
         
-        DateTime date = request.getIssueInstant();
+        Instant date = request.getIssueInstant();
         Assert.assertNull(date, "IssueInstant attribute has a value of " + date + ", expected no value");
 
         Assert.assertNull(request.getQuery(), "Query has value");
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ResponseTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ResponseTest.java
index d09770f..69b4668 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ResponseTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml1/core/impl/ResponseTest.java
@@ -23,10 +23,11 @@ package org.opensaml.saml.saml1.core.impl;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.saml1.core.Assertion;
@@ -47,7 +48,7 @@ public class ResponseTest extends XMLObjectProviderBaseTestCase {
     private final String expectedID;
 
     /** Representation of IssueInstant in test file. */
-    private final DateTime expectedIssueInstant;
+    private final Instant expectedIssueInstant;
 
     /** Representation of InResponseTo in test file. */
     private final String expectedInResponseTo;
@@ -66,10 +67,7 @@ public class ResponseTest extends XMLObjectProviderBaseTestCase {
         singleElementFile = "/org/opensaml/saml/saml1/impl/singleResponse.xml";
         singleElementOptionalAttributesFile = "/org/opensaml/saml/saml1/impl/singleResponseAttributes.xml";
         childElementsFile = "/org/opensaml/saml/saml1/impl/ResponseWithChildren.xml";
-        //
-        // IssueInstant="1970-01-01T00:00:00.100Z"
-        //
-        expectedIssueInstant = new DateTime(1970, 1, 1, 0, 0, 0, 100, ISOChronology.getInstanceUTC());
+        expectedIssueInstant = Instant.parse("1970-01-01T00:00:00.100Z");
 
         expectedInResponseTo="inresponseto";
         expectedMinorVersion=1;
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java
index 078f0f8..a4b9439 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/BaseAssertionValidationTest.java
@@ -27,13 +27,14 @@ import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.core.xml.XMLObjectBuilder;
 import org.opensaml.core.xml.io.MarshallingException;
@@ -77,7 +78,7 @@ public class BaseAssertionValidationTest extends XMLObjectBaseTestCase {
     @BeforeMethod
     protected void setUpBasicAssertion() {
         assertion = SAML2ActionTestingSupport.buildAssertion();
-        assertion.setIssueInstant(new DateTime());
+        assertion.setIssueInstant(Instant.now());
         assertion.setIssuer(SAML2ActionTestingSupport.buildIssuer(ISSUER));
         assertion.setSubject(SAML2ActionTestingSupport.buildSubject(PRINCIPAL_NAME));
         assertion.setConditions(buildBasicConditions());
@@ -91,9 +92,9 @@ public class BaseAssertionValidationTest extends XMLObjectBaseTestCase {
     
     protected Conditions buildBasicConditions() {
         Conditions conditions = buildXMLObject(Conditions.DEFAULT_ELEMENT_NAME);
-        DateTime now = new DateTime();
-        conditions.setNotBefore(now.minusMinutes(5));
-        conditions.setNotOnOrAfter(now.plusMinutes(5));
+        Instant now = Instant.now();
+        conditions.setNotBefore(now.minus(5, ChronoUnit.MINUTES));
+        conditions.setNotOnOrAfter(now.plus(5, ChronoUnit.MINUTES));
         return conditions;
     }
     
@@ -112,9 +113,9 @@ public class BaseAssertionValidationTest extends XMLObjectBaseTestCase {
        }
        scd.setRecipient(SUBJECT_CONFIRMATION_RECIPIENT);
        scd.setAddress(SUBJECT_CONFIRMATION_ADDRESS);
-       DateTime now = new DateTime();
-       scd.setNotBefore(now.minusMinutes(5));
-       scd.setNotOnOrAfter(now.plusMinutes(5));
+       Instant now = Instant.now();
+       scd.setNotBefore(now.minus(5, ChronoUnit.MINUTES));
+       scd.setNotOnOrAfter(now.plus(5, ChronoUnit.MINUTES));
        return scd;
     }
     
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidatorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidatorTest.java
index 50d93b0..42a0850 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidatorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/SAML20AssertionValidatorTest.java
@@ -25,6 +25,8 @@ import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -37,7 +39,6 @@ import javax.xml.namespace.QName;
 
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.common.assertion.AssertionValidationException;
@@ -329,8 +330,8 @@ public class SAML20AssertionValidatorTest extends BaseAssertionValidationTest {
     
     @Test
     public void testInvalidConditionsNotBefore() throws AssertionValidationException {
-        getAssertion().getConditions().setNotBefore(new DateTime().plusMinutes(30));
-        getAssertion().getConditions().setNotOnOrAfter(new DateTime().plusMinutes(60));
+        getAssertion().getConditions().setNotBefore(Instant.now().plus(30, ChronoUnit.MINUTES));
+        getAssertion().getConditions().setNotOnOrAfter(Instant.now().plus(60, ChronoUnit.MINUTES));
         
         validator = getCurrentValidator();
         
@@ -346,8 +347,8 @@ public class SAML20AssertionValidatorTest extends BaseAssertionValidationTest {
     
     @Test
     public void testInvalidConditionsNotOnOrAfter() throws AssertionValidationException {
-        getAssertion().getConditions().setNotBefore(new DateTime().minusMinutes(60));
-        getAssertion().getConditions().setNotOnOrAfter(new DateTime().minusMinutes(30));
+        getAssertion().getConditions().setNotBefore(Instant.now().minus(60, ChronoUnit.MINUTES));
+        getAssertion().getConditions().setNotOnOrAfter(Instant.now().minus(30, ChronoUnit.MINUTES));
         
         validator = getCurrentValidator();
         
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java
index 8f94a11..f4aa843 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/assertion/impl/AbstractSubjectConfirmationValidatorTest.java
@@ -17,11 +17,12 @@
 
 package org.opensaml.saml.saml2.assertion.impl;
 
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
 
-import org.joda.time.DateTime;
 import org.opensaml.saml.common.assertion.AssertionValidationException;
 import org.opensaml.saml.common.assertion.ValidationContext;
 import org.opensaml.saml.common.assertion.ValidationResult;
@@ -156,8 +157,8 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
     @Test
     public void testInvalidNotBefore() throws AssertionValidationException {
         // Adjust them both just so they make sense
-        subjectConfirmation.getSubjectConfirmationData().setNotBefore(new DateTime().plusMinutes(30));
-        subjectConfirmation.getSubjectConfirmationData().setNotOnOrAfter(new DateTime().plusMinutes(60));
+        subjectConfirmation.getSubjectConfirmationData().setNotBefore(Instant.now().plus(30, ChronoUnit.MINUTES));
+        subjectConfirmation.getSubjectConfirmationData().setNotOnOrAfter(Instant.now().plus(60, ChronoUnit.MINUTES));
         
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
@@ -178,8 +179,8 @@ public class AbstractSubjectConfirmationValidatorTest extends BaseAssertionValid
     @Test
     public void testInvalidNotOnOrAfter() throws AssertionValidationException {
         // Adjust them both just so they make sense
-        subjectConfirmation.getSubjectConfirmationData().setNotBefore(new DateTime().minusMinutes(60));
-        subjectConfirmation.getSubjectConfirmationData().setNotOnOrAfter(new DateTime().minusMinutes(30));
+        subjectConfirmation.getSubjectConfirmationData().setNotBefore(Instant.now().minus(60, ChronoUnit.MINUTES));
+        subjectConfirmation.getSubjectConfirmationData().setNotOnOrAfter(Instant.now().minus(30, ChronoUnit.MINUTES));
         
         ValidationContext validationContext = new ValidationContext(buildBasicStaticParameters());
         
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java
index 44fc5f3..2146121 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostEncoderTest.java
@@ -18,11 +18,11 @@
 package org.opensaml.saml.saml2.binding.encoding.impl;
 
 import java.io.ByteArrayInputStream;
+import java.time.Instant;
 import java.util.List;
 
 import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.runtime.RuntimeConstants;
-import org.joda.time.DateTime;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.DocumentType;
@@ -93,7 +93,7 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
         Response samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setStatus(responseStatus);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
@@ -188,7 +188,7 @@ public class HTTPPostEncoderTest extends XMLObjectBaseTestCase {
         AuthnRequest samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
                 .getBuilder(AssertionConsumerService.DEFAULT_ELEMENT_NAME);
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java
index 3e09cfc..b385ddf 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPPostSimpleSignEncoderTest.java
@@ -19,11 +19,11 @@ package org.opensaml.saml.saml2.binding.encoding.impl;
 
 import java.io.ByteArrayInputStream;
 import java.security.KeyPair;
+import java.time.Instant;
 import java.util.List;
 
 import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.runtime.RuntimeConstants;
-import org.joda.time.DateTime;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.DocumentType;
@@ -103,7 +103,7 @@ public class HTTPPostSimpleSignEncoderTest extends XMLObjectBaseTestCase {
         Response samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setStatus(responseStatus);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
@@ -201,7 +201,7 @@ public class HTTPPostSimpleSignEncoderTest extends XMLObjectBaseTestCase {
         AuthnRequest samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
                 .getBuilder(AssertionConsumerService.DEFAULT_ELEMENT_NAME);
@@ -295,7 +295,7 @@ public class HTTPPostSimpleSignEncoderTest extends XMLObjectBaseTestCase {
         AuthnRequest samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
                 .getBuilder(AssertionConsumerService.DEFAULT_ELEMENT_NAME);
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPRedirectDeflateEncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPRedirectDeflateEncoderTest.java
index 31a9887..99cb0a4 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPRedirectDeflateEncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPRedirectDeflateEncoderTest.java
@@ -19,11 +19,11 @@ package org.opensaml.saml.saml2.binding.encoding.impl;
 
 import java.io.ByteArrayInputStream;
 import java.security.KeyPair;
+import java.time.Instant;
 import java.util.Map;
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.messaging.context.MessageContext;
 import org.opensaml.saml.common.SAMLObject;
@@ -80,7 +80,7 @@ public class HTTPRedirectDeflateEncoderTest extends XMLObjectBaseTestCase {
         Response samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setStatus(responseStatus);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
@@ -157,7 +157,7 @@ public class HTTPRedirectDeflateEncoderTest extends XMLObjectBaseTestCase {
         Response samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setStatus(responseStatus);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
@@ -238,7 +238,7 @@ public class HTTPRedirectDeflateEncoderTest extends XMLObjectBaseTestCase {
         Response samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setStatus(responseStatus);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
@@ -323,7 +323,7 @@ public class HTTPRedirectDeflateEncoderTest extends XMLObjectBaseTestCase {
         Response samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setStatus(responseStatus);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPSOAP11EncoderTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPSOAP11EncoderTest.java
index dea5646..f5d461c 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPSOAP11EncoderTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/binding/encoding/impl/HTTPSOAP11EncoderTest.java
@@ -18,8 +18,8 @@
 package org.opensaml.saml.saml2.binding.encoding.impl;
 
 import java.io.ByteArrayInputStream;
+import java.time.Instant;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
 import org.opensaml.core.xml.util.XMLObjectSupport;
@@ -68,7 +68,7 @@ public class HTTPSOAP11EncoderTest extends XMLObjectBaseTestCase {
         Response samlMessage = responseBuilder.buildObject();
         samlMessage.setID("foo");
         samlMessage.setVersion(SAMLVersion.VERSION_20);
-        samlMessage.setIssueInstant(new DateTime(0));
+        samlMessage.setIssueInstant(Instant.ofEpochMilli(0));
         samlMessage.setStatus(responseStatus);
 
         SAMLObjectBuilder<Endpoint> endpointBuilder = (SAMLObjectBuilder<Endpoint>) builderFactory
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/AuthnRequestTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/AuthnRequestTest.java
index 440489b..cb49fe0 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/AuthnRequestTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/AuthnRequestTest.java
@@ -19,8 +19,9 @@ package org.opensaml.saml.saml2.core;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+
+import java.time.Instant;
+
 import org.opensaml.core.xml.schema.XSBooleanValue;
 import org.opensaml.saml.common.BaseComplexSAMLObjectTestCase;
 import org.opensaml.saml.common.SAMLVersion;
@@ -58,7 +59,7 @@ public class AuthnRequestTest extends BaseComplexSAMLObjectTestCase {
         Assert.assertEquals(request.getProviderName(), "SomeProvider", "ProviderName");
         Assert.assertEquals(request.getID(), "abe567de6", "ID");
         Assert.assertEquals(request.getVersion().toString(), SAMLVersion.VERSION_20.toString(), "Version");
-        Assert.assertEquals(request.getIssueInstant(), new DateTime(2005, 1, 31, 12, 0, 0, 0, ISOChronology.getInstanceUTC()), "IssueInstant");
+        Assert.assertEquals(request.getIssueInstant(), Instant.parse("2005-01-31T12:00:00.000Z"), "IssueInstant");
         Assert.assertEquals(request.getDestination(), "http://www.example.com/", "Destination");
         Assert.assertEquals(request.getConsent(), "urn:oasis:names:tc:SAML:2.0:consent:obtained", "Consent");
         Assert.assertEquals(request.getSubject().getNameID().getFormat(), "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Subject/NameID/@NameIdFormat");
@@ -105,7 +106,7 @@ public class AuthnRequestTest extends BaseComplexSAMLObjectTestCase {
         request.setProviderName("SomeProvider");
         request.setID("abe567de6");
         request.setVersion(SAMLVersion.VERSION_20);
-        request.setIssueInstant(new DateTime(2005, 1, 31, 12, 0, 0, 0, ISOChronology.getInstanceUTC()));
+        request.setIssueInstant(Instant.parse("2005-01-31T12:00:00.000Z"));
         request.setDestination("http://www.example.com/");
         request.setConsent("urn:oasis:names:tc:SAML:2.0:consent:obtained");
         
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/ResponseSuccessAuthnAttribTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/ResponseSuccessAuthnAttribTest.java
index 86ec7a1..f42c3d3 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/ResponseSuccessAuthnAttribTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/ResponseSuccessAuthnAttribTest.java
@@ -19,8 +19,9 @@ package org.opensaml.saml.saml2.core;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectBuilder;
 import org.opensaml.core.xml.schema.XSString;
 import org.opensaml.saml.common.BaseComplexSAMLObjectTestCase;
@@ -64,27 +65,27 @@ public class ResponseSuccessAuthnAttribTest extends BaseComplexSAMLObjectTestCas
         Assert.assertEquals(response.getID(), "_c7055387-af61-4fce-8b98-e2927324b306", "Response ID");
         Assert.assertEquals(response.getInResponseTo(), "_abcdef123456", "InResponseTo");
         Assert.assertEquals(response.getVersion().toString(), SAMLVersion.VERSION_20.toString(), "Version");
-        Assert.assertEquals(response.getIssueInstant(), new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()), "IssueInstant");
+        Assert.assertEquals(response.getIssueInstant(), Instant.parse("2006-01-26T13:35:05.000Z"), "IssueInstant");
         Assert.assertEquals(response.getIssuer().getFormat(), "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", "Issuer/@Format");
         Assert.assertEquals(response.getStatus().getStatusCode().getValue(), "urn:oasis:names:tc:SAML:2.0:status:Success", "Status/Statuscode/@Value");
         
         Assertion assertion = (Assertion) response.getAssertions().get(0);
         Assert.assertNotNull(assertion, "Assertion[0] was null");
         Assert.assertEquals(assertion.getID(), "_a75adf55-01d7-40cc-929f-dbd8372ebdfc", "Assertion ID");
-        Assert.assertEquals(assertion.getIssueInstant(), new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()), "Assertion/@IssueInstant");
+        Assert.assertEquals(assertion.getIssueInstant(), Instant.parse("2006-01-26T13:35:05.000Z"), "Assertion/@IssueInstant");
         Assert.assertEquals(assertion.getVersion().toString(), SAMLVersion.VERSION_20.toString(), "Assertion/@Version");
         Assert.assertEquals(assertion.getIssuer().getFormat(), "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", "Assertion/Issuer/@Format");
         Assert.assertEquals(assertion.getSubject().getNameID().getFormat(), "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "Assertion/Subject/NameID/@Format");
         Assert.assertEquals(assertion.getSubject().getNameID().getValue(), "_820d2843-2342-8236-ad28-8ac94fb3e6a1", "Assertion/Subject/NameID contents");
         SubjectConfirmation sc = assertion.getSubject().getSubjectConfirmations().get(0);
         Assert.assertEquals(sc.getMethod(), "urn:oasis:names:tc:SAML:2.0:cm:bearer", "Assertion/Subject/SubjectConfirmation/@Method");
-        Assert.assertEquals(assertion.getConditions().getNotBefore(), new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()), "Assertion/Condition/@NotBefore");
-        Assert.assertEquals(assertion.getConditions().getNotOnOrAfter(), new DateTime(2006, 1, 26, 13, 45, 5, 0, ISOChronology.getInstanceUTC()), "Assertion/Condition/@NotOnOrAfter");
+        Assert.assertEquals(assertion.getConditions().getNotBefore(), Instant.parse("2006-01-26T13:35:05.000Z"), "Assertion/Condition/@NotBefore");
+        Assert.assertEquals(assertion.getConditions().getNotOnOrAfter(), Instant.parse("2006-01-26T13:45:05.000Z"), "Assertion/Condition/@NotOnOrAfter");
         Audience audience = (Audience) assertion.getConditions().getAudienceRestrictions().get(0).getAudiences().get(0);
         Assert.assertEquals(audience.getAudienceURI(), "https://sp.example.org", "Assertion/Conditions/AudienceRestriction/Audience contents");
         
         AuthnStatement authnStatement = (AuthnStatement) assertion.getAuthnStatements().get(0);
-        Assert.assertEquals(authnStatement.getAuthnInstant(), new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()), "Assertion/AuthnStatement/@AuthnInstant");
+        Assert.assertEquals(authnStatement.getAuthnInstant(), Instant.parse("2006-01-26T13:35:05.000Z"), "Assertion/AuthnStatement/@AuthnInstant");
         Assert.assertEquals(authnStatement.getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef(), "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport", "Assertion/AuthnStatement/AuthnContext/AuthnContextClassRef contents");
         
         AttributeStatement  attribStatement = (AttributeStatement) assertion.getAttributeStatements().get(0);
@@ -116,7 +117,7 @@ public class ResponseSuccessAuthnAttribTest extends BaseComplexSAMLObjectTestCas
         Response response = (Response) buildXMLObject(Response.DEFAULT_ELEMENT_NAME);
         response.setID("_c7055387-af61-4fce-8b98-e2927324b306");
         response.setInResponseTo("_abcdef123456");
-        response.setIssueInstant(new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()));
+        response.setIssueInstant(Instant.parse("2006-01-26T13:35:05.000Z"));
         
         Issuer rIssuer = (Issuer) buildXMLObject(Issuer.DEFAULT_ELEMENT_NAME);
         rIssuer.setFormat("urn:oasis:names:tc:SAML:2.0:nameid-format:entity");
@@ -128,7 +129,7 @@ public class ResponseSuccessAuthnAttribTest extends BaseComplexSAMLObjectTestCas
         
         Assertion assertion = (Assertion) buildXMLObject(Assertion.DEFAULT_ELEMENT_NAME);
         assertion.setID("_a75adf55-01d7-40cc-929f-dbd8372ebdfc");
-        assertion.setIssueInstant(new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()));
+        assertion.setIssueInstant(Instant.parse("2006-01-26T13:35:05.000Z"));
         
         Issuer aIssuer = (Issuer) buildXMLObject(Issuer.DEFAULT_ELEMENT_NAME);
         aIssuer.setFormat("urn:oasis:names:tc:SAML:2.0:nameid-format:entity");
@@ -143,15 +144,15 @@ public class ResponseSuccessAuthnAttribTest extends BaseComplexSAMLObjectTestCas
         subjectConfirmation.setMethod("urn:oasis:names:tc:SAML:2.0:cm:bearer");
         
         Conditions conditions = (Conditions) buildXMLObject(Conditions.DEFAULT_ELEMENT_NAME);
-        conditions.setNotBefore(new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()));
-        conditions.setNotOnOrAfter(new DateTime(2006, 1, 26, 13, 45, 5, 0, ISOChronology.getInstanceUTC()));
+        conditions.setNotBefore(Instant.parse("2006-01-26T13:35:05.000Z"));
+        conditions.setNotOnOrAfter(Instant.parse("2006-01-26T13:45:05.000Z"));
         
         AudienceRestriction audienceRestriction = (AudienceRestriction) buildXMLObject(AudienceRestriction.DEFAULT_ELEMENT_NAME);
         Audience audience = (Audience) buildXMLObject(Audience.DEFAULT_ELEMENT_NAME);
         audience.setAudienceURI("https://sp.example.org");
         
         AuthnStatement authnStatement = (AuthnStatement) buildXMLObject(AuthnStatement.DEFAULT_ELEMENT_NAME);
-        authnStatement.setAuthnInstant(new DateTime(2006, 1, 26, 13, 35, 5, 0, ISOChronology.getInstanceUTC()));
+        authnStatement.setAuthnInstant(Instant.parse("2006-01-26T13:35:05.000Z"));
         
         AuthnContext authnContext = (AuthnContext) buildXMLObject(AuthnContext.DEFAULT_ELEMENT_NAME);
         AuthnContextClassRef classRef = (AuthnContextClassRef) buildXMLObject(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/SignedAssertionTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/SignedAssertionTest.java
index 7075200..4265448 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/SignedAssertionTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/SignedAssertionTest.java
@@ -21,12 +21,12 @@ import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
 import java.security.KeyPair;
+import java.time.Instant;
 
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.security.RandomIdentifierGenerationStrategy;
 import net.shibboleth.utilities.java.support.xml.SerializeSupport;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.core.xml.io.Marshaller;
 import org.opensaml.core.xml.io.MarshallingException;
@@ -105,7 +105,7 @@ public class SignedAssertionTest extends XMLObjectBaseTestCase {
     @Test
     public void testAssertionSignature() 
         throws MarshallingException, SignatureException, UnmarshallingException, SecurityException{
-        DateTime now = new DateTime();
+        Instant now = Instant.now();
         
         Assertion assertion = assertionBuilder.buildObject();
         assertion.setVersion(SAMLVersion.VERSION_20);
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AssertionTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AssertionTest.java
index 7458939..79d3384 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AssertionTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AssertionTest.java
@@ -23,10 +23,11 @@ import net.shibboleth.utilities.java.support.xml.XMLParserException;
 
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.saml.common.SAMLVersion;
@@ -49,7 +50,7 @@ public class AssertionTest extends XMLObjectProviderBaseTestCase {
     private SAMLVersion expectedVersion;
     
     /** Expected IssueInstant value */
-    private DateTime expectedIssueInstant;
+    private Instant expectedIssueInstant;
 
     /** Expected ID value */
     private String expectedID;
@@ -76,7 +77,7 @@ public class AssertionTest extends XMLObjectProviderBaseTestCase {
     @BeforeMethod
     protected void setUp() throws Exception {
         expectedVersion = SAMLVersion.VERSION_20;
-        expectedIssueInstant = new DateTime(1984, 8, 26, 10, 01, 30, 43, ISOChronology.getInstanceUTC());
+        expectedIssueInstant = Instant.parse("1984-08-26T10:01:30.043Z");
         expectedID = "id";
     }
 
@@ -85,7 +86,7 @@ public class AssertionTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementUnmarshall() {
         Assertion assertion = (Assertion) unmarshallElement(singleElementFile);
 
-        DateTime notBefore = assertion.getIssueInstant();
+        Instant notBefore = assertion.getIssueInstant();
         Assert.assertEquals(notBefore, expectedIssueInstant,
                 "IssueInstant was " + notBefore + ", expected " + expectedIssueInstant);
     }
@@ -95,7 +96,7 @@ public class AssertionTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementOptionalAttributesUnmarshall() {
         Assertion assertion = (Assertion) unmarshallElement(singleElementOptionalAttributesFile);
 
-        DateTime issueInstant = assertion.getIssueInstant();
+        Instant issueInstant = assertion.getIssueInstant();
         Assert.assertEquals(issueInstant, expectedIssueInstant,
                 "IssueInstant was " + issueInstant + ", expected " + expectedIssueInstant);
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AuthnStatementTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AuthnStatementTest.java
index b96fedc..a5eb812 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AuthnStatementTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/AuthnStatementTest.java
@@ -20,8 +20,9 @@ package org.opensaml.saml.saml2.core.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+
+import java.time.Instant;
+
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.saml2.core.AuthnContext;
 import org.opensaml.saml.saml2.core.AuthnStatement;
@@ -33,13 +34,13 @@ import org.opensaml.saml.saml2.core.SubjectLocality;
 public class AuthnStatementTest extends XMLObjectProviderBaseTestCase {
 
     /** Expected AuthnInstant value */
-    private DateTime expectedAuthnInstant;
+    private Instant expectedAuthnInstant;
 
     /** Expected SessionIndex value */
     private String expectedSessionIndex;
 
     /** Expected SessionNotOnOrAfter value */
-    private DateTime expectedSessionNotOnOrAfter;
+    private Instant expectedSessionNotOnOrAfter;
 
     /** Constructor */
     public AuthnStatementTest() {
@@ -50,9 +51,9 @@ public class AuthnStatementTest extends XMLObjectProviderBaseTestCase {
 
     @BeforeMethod
     protected void setUp() throws Exception {
-        expectedAuthnInstant = new DateTime(1984, 8, 26, 10, 01, 30, 43, ISOChronology.getInstanceUTC());
+        expectedAuthnInstant = Instant.parse("1984-08-26T10:01:30.043Z");
         expectedSessionIndex = "index";
-        expectedSessionNotOnOrAfter = new DateTime(1984, 8, 26, 10, 11, 30, 43, ISOChronology.getInstanceUTC());
+        expectedSessionNotOnOrAfter = Instant.parse("1984-08-26T10:11:30.043Z");
     }
 
     /** {@inheritDoc} */
@@ -60,7 +61,7 @@ public class AuthnStatementTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementUnmarshall() {
         AuthnStatement authnStatement = (AuthnStatement) unmarshallElement(singleElementFile);
 
-        DateTime authnInstant = authnStatement.getAuthnInstant();
+        Instant authnInstant = authnStatement.getAuthnInstant();
         Assert.assertEquals(authnInstant, expectedAuthnInstant,
                 "AuthnInstant was " + authnInstant + ", expected " + expectedAuthnInstant);
     }
@@ -70,7 +71,7 @@ public class AuthnStatementTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementOptionalAttributesUnmarshall() {
         AuthnStatement authnStatement = (AuthnStatement) unmarshallElement(singleElementOptionalAttributesFile);
 
-        DateTime authnInstant = authnStatement.getAuthnInstant();
+        Instant authnInstant = authnStatement.getAuthnInstant();
         Assert.assertEquals(authnInstant, expectedAuthnInstant,
                 "AuthnInstant was " + authnInstant + ", expected " + expectedAuthnInstant);
 
@@ -78,7 +79,7 @@ public class AuthnStatementTest extends XMLObjectProviderBaseTestCase {
         Assert.assertEquals(sessionIndex, expectedSessionIndex,
                 "SessionIndex was " + sessionIndex + ", expected " + expectedSessionIndex);
 
-        DateTime sessionNotOnOrAfter = authnStatement.getSessionNotOnOrAfter();
+        Instant sessionNotOnOrAfter = authnStatement.getSessionNotOnOrAfter();
         Assert.assertEquals(sessionNotOnOrAfter,
                 expectedSessionNotOnOrAfter, "SessionNotOnOrAfter was " + sessionNotOnOrAfter + ", expected " + expectedSessionNotOnOrAfter);
     }
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/ConditionsTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/ConditionsTest.java
index 7cb7aef..330f681 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/ConditionsTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/ConditionsTest.java
@@ -20,10 +20,11 @@ package org.opensaml.saml.saml2.core.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.core.AudienceRestriction;
@@ -38,10 +39,10 @@ import org.opensaml.saml.saml2.core.ProxyRestriction;
 public class ConditionsTest extends XMLObjectProviderBaseTestCase {
 
     /** Expected NotBefore value */
-    private DateTime expectedNotBefore;
+    private Instant expectedNotBefore;
 
     /** Expected NotOnOrAfter value */
-    private DateTime expectedNotOnOrAfter;
+    private Instant expectedNotOnOrAfter;
 
     /** Count of Condition subelements */
     private int conditionCount = 6;
@@ -58,8 +59,8 @@ public class ConditionsTest extends XMLObjectProviderBaseTestCase {
 
     @BeforeMethod
     protected void setUp() throws Exception {
-        expectedNotBefore = new DateTime(1984, 8, 26, 10, 01, 30, 43, ISOChronology.getInstanceUTC());
-        expectedNotOnOrAfter = new DateTime(1984, 8, 26, 10, 11, 30, 43, ISOChronology.getInstanceUTC());
+        expectedNotBefore = Instant.parse("1984-08-26T10:01:30.043Z");
+        expectedNotOnOrAfter = Instant.parse("1984-08-26T10:11:30.043Z");
     }
 
     /** {@inheritDoc} */
@@ -67,7 +68,7 @@ public class ConditionsTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementUnmarshall() {
         Conditions conditions = (Conditions) unmarshallElement(singleElementFile);
 
-        DateTime notBefore = conditions.getNotBefore();
+        Instant notBefore = conditions.getNotBefore();
         Assert.assertEquals(notBefore, expectedNotBefore, "NotBefore was " + notBefore + ", expected " + expectedNotBefore);
     }
 
@@ -76,10 +77,10 @@ public class ConditionsTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementOptionalAttributesUnmarshall() {
         Conditions conditions = (Conditions) unmarshallElement(singleElementOptionalAttributesFile);
 
-        DateTime notBefore = conditions.getNotBefore();
+        Instant notBefore = conditions.getNotBefore();
         Assert.assertEquals(notBefore, expectedNotBefore, "NotBefore was " + notBefore + ", expected " + expectedNotBefore);
 
-        DateTime notOnOrAfter = conditions.getNotOnOrAfter();
+        Instant notOnOrAfter = conditions.getNotOnOrAfter();
         Assert.assertEquals(notOnOrAfter, expectedNotOnOrAfter,
                 "NotOnOrAfter was " + notOnOrAfter + ", expected " + expectedNotOnOrAfter);
     }
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/KeyInfoConfirmationDataTypeTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/KeyInfoConfirmationDataTypeTest.java
index 4fc17bd..862da0b 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/KeyInfoConfirmationDataTypeTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/KeyInfoConfirmationDataTypeTest.java
@@ -20,10 +20,11 @@ package org.opensaml.saml.saml2.core.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.saml.common.SAMLObjectBuilder;
@@ -38,10 +39,10 @@ import org.opensaml.xmlsec.signature.KeyInfo;
 public class KeyInfoConfirmationDataTypeTest extends XMLObjectProviderBaseTestCase {
 
     /** Expected NotBefore value. */
-    private DateTime expectedNotBefore;
+    private Instant expectedNotBefore;
 
     /** Expected NotOnOrAfter value. */
-    private DateTime expectedNotOnOrAfter;
+    private Instant expectedNotOnOrAfter;
 
     /** Expected Recipient value. */
     private String expectedRecipient;
@@ -67,8 +68,8 @@ public class KeyInfoConfirmationDataTypeTest extends XMLObjectProviderBaseTestCa
 
     @BeforeMethod
     protected void setUp() throws Exception {
-        expectedNotBefore = new DateTime(1984, 8, 26, 10, 01, 30, 43, ISOChronology.getInstanceUTC());
-        expectedNotOnOrAfter = new DateTime(1984, 8, 26, 10, 11, 30, 43, ISOChronology.getInstanceUTC());
+        expectedNotBefore = Instant.parse("1984-08-26T10:01:30.043Z");
+        expectedNotOnOrAfter = Instant.parse("1984-08-26T10:11:30.043Z");
         expectedRecipient = "recipient";
         expectedInResponseTo = "inresponse";
         expectedAddress = "address";
@@ -91,10 +92,10 @@ public class KeyInfoConfirmationDataTypeTest extends XMLObjectProviderBaseTestCa
     public void testSingleElementOptionalAttributesUnmarshall() {
         KeyInfoConfirmationDataType kicd = (KeyInfoConfirmationDataType) unmarshallElement(singleElementOptionalAttributesFile);
 
-        DateTime notBefore = kicd.getNotBefore();
+        Instant notBefore = kicd.getNotBefore();
         Assert.assertEquals(notBefore, expectedNotBefore, "NotBefore was " + notBefore + ", expected " + expectedNotBefore);
 
-        DateTime notOnOrAfter = kicd.getNotOnOrAfter();
+        Instant notOnOrAfter = kicd.getNotOnOrAfter();
         Assert.assertEquals(notOnOrAfter, expectedNotOnOrAfter,
                 "NotOnOrAfter was " + notOnOrAfter + ", expected " + expectedNotOnOrAfter);
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/LogoutRequestTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/LogoutRequestTest.java
index c00833c..c957858 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/LogoutRequestTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/LogoutRequestTest.java
@@ -23,10 +23,11 @@ package org.opensaml.saml.saml2.core.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.core.LogoutRequest;
 import org.opensaml.saml.saml2.core.NameID;
@@ -41,7 +42,7 @@ public class LogoutRequestTest extends RequestTestBase {
     private String expectedReason;
     
     /** Expected NotOnOrAfter attribute value */
-    private DateTime expectedNotOnOrAfter;
+    private Instant expectedNotOnOrAfter;
     
     /** Expected number of SessionIndex child elements */
     private int expectedNumSessionIndexes;
@@ -61,7 +62,7 @@ public class LogoutRequestTest extends RequestTestBase {
     protected void setUp() throws Exception {
         super.setUp();
         expectedReason = "urn:string:reason";
-        expectedNotOnOrAfter = new DateTime(2006, 2, 21, 20, 45, 0, 0, ISOChronology.getInstanceUTC());
+        expectedNotOnOrAfter = Instant.parse("2006-02-21T20:45:00.000Z");
         expectedNumSessionIndexes = 2;
     }
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/RequestTestBase.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/RequestTestBase.java
index ed4ff3d..5a9e53f 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/RequestTestBase.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/RequestTestBase.java
@@ -20,10 +20,11 @@ package org.opensaml.saml.saml2.core.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.SAMLVersion;
@@ -43,7 +44,7 @@ public abstract class RequestTestBase extends XMLObjectProviderBaseTestCase {
     protected SAMLVersion expectedSAMLVersion;
 
     /** Expected IssueInstant attribute */
-    protected DateTime expectedIssueInstant;
+    protected Instant expectedIssueInstant;
 
     /** Expected Destination attribute */
     protected String expectedDestination;
@@ -66,7 +67,7 @@ public abstract class RequestTestBase extends XMLObjectProviderBaseTestCase {
     protected void setUp() throws Exception {
         expectedID = "abc123";
         expectedSAMLVersion = SAMLVersion.VERSION_20;
-        expectedIssueInstant = new DateTime(2006, 2, 21, 16, 40, 0, 0, ISOChronology.getInstanceUTC());
+        expectedIssueInstant = Instant.parse("2006-02-21T16:40:00.000Z");
         expectedDestination = "http://idp.example.org/endpoint";
         expectedConsent = "urn:string:consent";
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/StatusResponseTestBase.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/StatusResponseTestBase.java
index bcdab06..ca2f190 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/StatusResponseTestBase.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/StatusResponseTestBase.java
@@ -23,10 +23,11 @@ package org.opensaml.saml.saml2.core.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.SAMLObject;
 import org.opensaml.saml.common.SAMLVersion;
@@ -50,7 +51,7 @@ public abstract class StatusResponseTestBase extends XMLObjectProviderBaseTestCa
     protected SAMLVersion expectedSAMLVersion;
     
     /** Expected IssueInstant attribute */
-    protected DateTime expectedIssueInstant;
+    protected Instant expectedIssueInstant;
     
     /** Expected Destination attribute */
     protected String expectedDestination;
@@ -77,7 +78,7 @@ public abstract class StatusResponseTestBase extends XMLObjectProviderBaseTestCa
         expectedID = "def456";
         expectedInResponseTo = "abc123";
         expectedSAMLVersion = SAMLVersion.VERSION_20;
-        expectedIssueInstant = new DateTime(2006, 2, 21, 16, 40, 0, 0, ISOChronology.getInstanceUTC());
+        expectedIssueInstant = Instant.parse("2006-02-21T16:40:00.000Z");
         expectedDestination = "http://sp.example.org/endpoint";
         expectedConsent = "urn:string:consent";
         
@@ -108,7 +109,7 @@ public abstract class StatusResponseTestBase extends XMLObjectProviderBaseTestCa
         
         sr.setID(expectedID);
         sr.setIssueInstant(expectedIssueInstant);
-        // NOTE:  the SAML Version attribute is set automatically by the impl superclas
+        // NOTE:  the SAML Version attribute is set automatically by the impl superclass
         
     }
     
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataTest.java
index c104621..c5e2017 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/core/impl/SubjectConfirmationDataTest.java
@@ -20,10 +20,11 @@ package org.opensaml.saml.saml2.core.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.core.SubjectConfirmationData;
@@ -35,10 +36,10 @@ import org.opensaml.saml.saml2.core.SubjectConfirmationData;
 public class SubjectConfirmationDataTest extends XMLObjectProviderBaseTestCase {
 
     /** Expected NotBefore value */
-    private DateTime expectedNotBefore;
+    private Instant expectedNotBefore;
 
     /** Expected NotOnOrAfter value */
-    private DateTime expectedNotOnOrAfter;
+    private Instant expectedNotOnOrAfter;
 
     /** Expected Recipient value */
     private String expectedRecipient;
@@ -57,8 +58,8 @@ public class SubjectConfirmationDataTest extends XMLObjectProviderBaseTestCase {
 
     @BeforeMethod
     protected void setUp() throws Exception {
-        expectedNotBefore = new DateTime(1984, 8, 26, 10, 01, 30, 43, ISOChronology.getInstanceUTC());
-        expectedNotOnOrAfter = new DateTime(1984, 8, 26, 10, 11, 30, 43, ISOChronology.getInstanceUTC());
+        expectedNotBefore = Instant.parse("1984-08-26T10:01:30.043Z");
+        expectedNotOnOrAfter = Instant.parse("1984-08-26T10:11:30.043Z");
         expectedRecipient = "recipient";
         expectedInResponseTo = "inresponse";
         expectedAddress = "address";
@@ -69,7 +70,7 @@ public class SubjectConfirmationDataTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementUnmarshall() {
         SubjectConfirmationData subjectCD = (SubjectConfirmationData) unmarshallElement(singleElementFile);
 
-        DateTime notBefore = subjectCD.getNotBefore();
+        Instant notBefore = subjectCD.getNotBefore();
         Assert.assertEquals(notBefore, expectedNotBefore, "NotBefore was " + notBefore + ", expected " + expectedNotBefore);
     }
 
@@ -78,10 +79,10 @@ public class SubjectConfirmationDataTest extends XMLObjectProviderBaseTestCase {
     public void testSingleElementOptionalAttributesUnmarshall() {
         SubjectConfirmationData subjectCD = (SubjectConfirmationData) unmarshallElement(singleElementOptionalAttributesFile);
 
-        DateTime notBefore = subjectCD.getNotBefore();
+        Instant notBefore = subjectCD.getNotBefore();
         Assert.assertEquals(notBefore, expectedNotBefore, "NotBefore was " + notBefore + ", expected " + expectedNotBefore);
 
-        DateTime notOnOrAfter = subjectCD.getNotOnOrAfter();
+        Instant notOnOrAfter = subjectCD.getNotOnOrAfter();
         Assert.assertEquals(notOnOrAfter, expectedNotOnOrAfter,
                 "NotOnOrAfter was " + notOnOrAfter + ", expected " + expectedNotOnOrAfter);
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/encryption/DecryptionPlusSigningTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/encryption/DecryptionPlusSigningTest.java
index c218cf7..cc788e9 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/encryption/DecryptionPlusSigningTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/encryption/DecryptionPlusSigningTest.java
@@ -25,11 +25,11 @@ import java.io.ByteArrayOutputStream;
 import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
+import java.time.Instant;
 
 import net.shibboleth.utilities.java.support.xml.SerializeSupport;
 import net.shibboleth.utilities.java.support.xml.XMLParserException;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.io.MarshallingException;
 import org.opensaml.core.xml.io.UnmarshallingException;
 import org.opensaml.core.xml.XMLObjectBaseTestCase;
@@ -126,7 +126,7 @@ public class DecryptionPlusSigningTest extends XMLObjectBaseTestCase {
         // Build Response container
         Response response = (Response) buildXMLObject(Response.DEFAULT_ELEMENT_NAME);
         response.setID("def456");
-        response.setIssueInstant(new DateTime());
+        response.setIssueInstant(Instant.now());
         
         Issuer issuer = (Issuer) buildXMLObject(Issuer.DEFAULT_ELEMENT_NAME);
         issuer.setValue("urn:string:issuer");
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorTest.java
index f7bd828..71e13c4 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AffiliationDescriptorTest.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.core.xml.util.AttributeMap;
 import org.opensaml.saml.common.xml.SAMLConstants;
@@ -49,7 +49,7 @@ public class AffiliationDescriptorTest extends XMLObjectProviderBaseTestCase {
     protected long expectedCacheDuration;
 
     /** Expected validUntil value */
-    protected DateTime expectedValidUntil;
+    protected Instant expectedValidUntil;
 
     /** Unknown Attributes */
     protected QName[] unknownAttributeNames = { new QName("urn:foo:bar", "bar", "foo") };
@@ -71,7 +71,7 @@ public class AffiliationDescriptorTest extends XMLObjectProviderBaseTestCase {
         expectedOwnerID = "urn:example.org";
         expectedID = "id";
         expectedCacheDuration = 90000;
-        expectedValidUntil = new DateTime(2005, 12, 7, 10, 21, 0, 0, ISOChronology.getInstanceUTC());
+        expectedValidUntil = Instant.parse("2005-12-07T10:21:00Z");
     }
 
     /** {@inheritDoc} */
@@ -86,7 +86,7 @@ public class AffiliationDescriptorTest extends XMLObjectProviderBaseTestCase {
         Long duration = descriptor.getCacheDuration();
         Assert.assertNull(duration, "cacheDuration attribute has a value of " + duration + ", expected no value");
 
-        DateTime validUntil = descriptor.getValidUntil();
+        Instant validUntil = descriptor.getValidUntil();
         Assert.assertNull(validUntil, "validUntil attribute has a value of " + validUntil + ", expected no value");
         
         Assert.assertTrue(descriptor.isValid());
@@ -108,7 +108,7 @@ public class AffiliationDescriptorTest extends XMLObjectProviderBaseTestCase {
         Assert.assertEquals(duration, expectedCacheDuration, "cacheDuration attribute has a value of " + duration + ", expected a value of "
                         + expectedCacheDuration);
 
-        DateTime validUntil = descriptor.getValidUntil();
+        Instant validUntil = descriptor.getValidUntil();
         Assert.assertEquals(expectedValidUntil
                 .compareTo(validUntil), 0, "validUntil attribute value did not match expected value");
         Assert.assertFalse(descriptor.isValid());
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AuthnAuthorityDescriptorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AuthnAuthorityDescriptorTest.java
index e86b6e4..0ffc7d0 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AuthnAuthorityDescriptorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/AuthnAuthorityDescriptorTest.java
@@ -20,13 +20,13 @@ package org.opensaml.saml.saml2.metadata.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.metadata.Extensions;
@@ -51,7 +51,7 @@ public class AuthnAuthorityDescriptorTest extends XMLObjectProviderBaseTestCase
     protected long expectedCacheDuration;
 
     /** Expected validUntil value */
-    protected DateTime expectedValidUntil;
+    protected Instant expectedValidUntil;
 
     /** Expected errorURL value */
     protected String expectedErrorURL;
@@ -85,7 +85,7 @@ public class AuthnAuthorityDescriptorTest extends XMLObjectProviderBaseTestCase
         expectedSupportedProtocols = new ArrayList<>();
         expectedSupportedProtocols.add(SAMLConstants.SAML20P_NS);
         expectedCacheDuration = 90000;
-        expectedValidUntil = new DateTime(2005, 12, 7, 10, 21, 0, 0, ISOChronology.getInstanceUTC());
+        expectedValidUntil = Instant.parse("2005-12-07T10:21:00Z");
         expectedErrorURL = "http://example.org";
         //
         // Element counts
@@ -108,7 +108,7 @@ public class AuthnAuthorityDescriptorTest extends XMLObjectProviderBaseTestCase
         Long duration = authnAuthorityObj.getCacheDuration();
         Assert.assertNull(duration, "cacheDuration attribute has a value of " + duration + ", expected no value");
 
-        DateTime validUntil = authnAuthorityObj.getValidUntil();
+        Instant validUntil = authnAuthorityObj.getValidUntil();
         Assert.assertNull(validUntil, "validUntil attribute has a value of " + validUntil + ", expected no value");
 
         String errorURL = authnAuthorityObj.getErrorURL();
@@ -128,7 +128,7 @@ public class AuthnAuthorityDescriptorTest extends XMLObjectProviderBaseTestCase
         Assert.assertEquals(duration, expectedCacheDuration, "cacheDuration attribute has a value of " + duration
                 + ", expected a value of " + expectedCacheDuration);
 
-        DateTime validUntil = authnAuthorityObj.getValidUntil();
+        Instant validUntil = authnAuthorityObj.getValidUntil();
         Assert.assertEquals(expectedValidUntil.compareTo(validUntil), 0,
                 "validUntil attribute value did not match expected value");
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorTest.java
index ea9c370..eb9fe22 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntitiesDescriptorTest.java
@@ -20,10 +20,11 @@ package org.opensaml.saml.saml2.metadata.impl;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
 import org.testng.Assert;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.metadata.Extensions;
@@ -48,7 +49,7 @@ public class EntitiesDescriptorTest extends XMLObjectProviderBaseTestCase {
     protected long expectedCacheDuration;
 
     /** Expected validUntil value */
-    protected DateTime expectedValidUntil;
+    protected Instant expectedValidUntil;
 
     /** Expected number of child EntitiesDescriptors */
     protected int expectedEntitiesDescriptorsCount;
@@ -70,7 +71,7 @@ public class EntitiesDescriptorTest extends XMLObjectProviderBaseTestCase {
         expectedID = "id";
         expectedName = "eDescName";
         expectedCacheDuration = 90000;
-        expectedValidUntil = new DateTime(2005, 12, 7, 10, 21, 0, 0, ISOChronology.getInstanceUTC());
+        expectedValidUntil = Instant.parse("2005-12-07T10:21:00.000Z");
         expectedEntitiesDescriptorsCount = 3;
         expectedEntityDescriptorsCount = 2;
     }
@@ -86,7 +87,7 @@ public class EntitiesDescriptorTest extends XMLObjectProviderBaseTestCase {
         Long duration = entitiesDescriptorObj.getCacheDuration();
         Assert.assertNull(duration, "cacheDuration attribute has a value of " + duration + ", expected no value");
 
-        DateTime validUntil = entitiesDescriptorObj.getValidUntil();
+        Instant validUntil = entitiesDescriptorObj.getValidUntil();
         Assert.assertNull(validUntil, "validUntil attribute has a value of " + validUntil + ", expected no value");
         Assert.assertTrue(entitiesDescriptorObj.isValid());
     }
@@ -107,7 +108,7 @@ public class EntitiesDescriptorTest extends XMLObjectProviderBaseTestCase {
         Assert.assertEquals(duration, expectedCacheDuration, "cacheDuration attribute has a value of " + duration + ", expected a value of "
                         + expectedCacheDuration);
 
-        DateTime validUntil = entitiesDescriptorObj.getValidUntil();
+        Instant validUntil = entitiesDescriptorObj.getValidUntil();
         Assert.assertEquals(expectedValidUntil
                 .compareTo(validUntil), 0, "validUntil attribute value did not match expected value");
         Assert.assertFalse(entitiesDescriptorObj.isValid());
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorTest.java
index e9262eb..c9c7f7c 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/EntityDescriptorTest.java
@@ -17,10 +17,10 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.core.xml.util.AttributeMap;
 import org.opensaml.saml.common.xml.SAMLConstants;
@@ -58,7 +58,7 @@ public class EntityDescriptorTest extends XMLObjectProviderBaseTestCase {
     protected long expectedCacheDuration;
 
     /** Expected validUntil value */
-    protected DateTime expectedValidUntil;
+    protected Instant expectedValidUntil;
 
     /** Unknown Attributes */
     protected QName[] unknownAttributeNames = {new QName("urn:foo:bar", "bar", "foo")};
@@ -83,7 +83,7 @@ public class EntityDescriptorTest extends XMLObjectProviderBaseTestCase {
         expectedID = "id";
         expectedEntityID = "99ff33";
         expectedCacheDuration = 90000;
-        expectedValidUntil = new DateTime(2005, 12, 7, 10, 21, 0, 0, ISOChronology.getInstanceUTC());
+        expectedValidUntil = Instant.parse("2005-12-07T10:21:00Z");
     }
 
     /** {@inheritDoc} */
@@ -97,7 +97,7 @@ public class EntityDescriptorTest extends XMLObjectProviderBaseTestCase {
         Long duration = descriptor.getCacheDuration();
         Assert.assertNull(duration, "cacheDuration attribute has a value of " + duration + ", expected no value");
 
-        DateTime validUntil = descriptor.getValidUntil();
+        Instant validUntil = descriptor.getValidUntil();
         Assert.assertNull(validUntil, "validUntil attribute has a value of " + validUntil + ", expected no value");
 
         Assert.assertTrue(descriptor.isValid());
@@ -118,7 +118,7 @@ public class EntityDescriptorTest extends XMLObjectProviderBaseTestCase {
         Assert.assertEquals(duration, expectedCacheDuration, "cacheDuration attribute has a value of " + duration
                 + ", expected a value of " + expectedCacheDuration);
 
-        DateTime validUntil = descriptor.getValidUntil();
+        Instant validUntil = descriptor.getValidUntil();
         Assert.assertEquals(expectedValidUntil.compareTo(validUntil), 0,
                 "validUntil attribute value did not match expected value");
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/IDPSSODescriptorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/IDPSSODescriptorTest.java
index dc9fd65..00b6f37 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/IDPSSODescriptorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/IDPSSODescriptorTest.java
@@ -17,12 +17,11 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.core.xml.schema.XSBooleanValue;
@@ -58,7 +57,7 @@ public class IDPSSODescriptorTest extends XMLObjectProviderBaseTestCase {
     protected long expectedCacheDuration;
 
     /** Expected validUntil value */
-    protected DateTime expectedValidUntil;
+    protected Instant expectedValidUntil;
 
     /** Expected error url */
     protected String expectedErrorURL;
@@ -90,7 +89,7 @@ public class IDPSSODescriptorTest extends XMLObjectProviderBaseTestCase {
         expectedSupportedProtocol.add("urn:fooz:baz");
 
         expectedCacheDuration = 90000;
-        expectedValidUntil = new DateTime(2005, 12, 7, 10, 21, 0, 0, ISOChronology.getInstanceUTC());
+        expectedValidUntil = Instant.parse("2005-12-07T10:21:00Z");
 
         expectedErrorURL = "http://example.org";
 
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/PDPDescriptorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/PDPDescriptorTest.java
index 39ec6c5..52891ef 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/PDPDescriptorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/PDPDescriptorTest.java
@@ -21,12 +21,11 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.metadata.Extensions;
@@ -51,7 +50,7 @@ public class PDPDescriptorTest extends XMLObjectProviderBaseTestCase {
     protected long expectedCacheDuration;
 
     /** Expected validUntil value */
-    protected DateTime expectedValidUntil;
+    protected Instant expectedValidUntil;
 
     /** Expected error url */
     protected String expectedErrorURL;
@@ -72,7 +71,7 @@ public class PDPDescriptorTest extends XMLObjectProviderBaseTestCase {
         expectedSupportedProtocol.add("urn:fooz:baz");
 
         expectedCacheDuration = 90000;
-        expectedValidUntil = new DateTime(2005, 12, 7, 10, 21, 0, 0, ISOChronology.getInstanceUTC());
+        expectedValidUntil = Instant.parse("2005-12-07T10:21:00Z");
 
         expectedErrorURL = "http://example.org";
     }
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/SPSSODescriptorTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/SPSSODescriptorTest.java
index 3b6573e..36361c9 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/SPSSODescriptorTest.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/metadata/impl/SPSSODescriptorTest.java
@@ -17,12 +17,11 @@
 
 package org.opensaml.saml.saml2.metadata.impl;
 
+import java.time.Instant;
 import java.util.ArrayList;
 
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
 import org.opensaml.core.xml.XMLObjectProviderBaseTestCase;
 import org.opensaml.core.xml.schema.XSBooleanValue;
 import org.opensaml.saml.common.xml.SAMLConstants;
@@ -60,7 +59,7 @@ public class SPSSODescriptorTest extends XMLObjectProviderBaseTestCase {
     protected long expectedCacheDuration;
 
     /** Expected validUntil value */
-    protected DateTime expectedValidUntil;
+    protected Instant expectedValidUntil;
     
     /** Expected Id */
     protected String expectedId;
@@ -84,7 +83,7 @@ public class SPSSODescriptorTest extends XMLObjectProviderBaseTestCase {
         expectedSupportedProtocol.add("urn:fooz:baz");
 
         expectedCacheDuration = 90000;
-        expectedValidUntil = new DateTime(2005, 12, 7, 10, 21, 0, 0, ISOChronology.getInstanceUTC());
+        expectedValidUntil = Instant.parse("2005-12-07T10:21:00Z");
         expectedId = "id";
     }
 
diff --git a/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/AttributedDateTime.java b/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/AttributedDateTime.java
index 29a4288..1fd6de1 100644
--- a/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/AttributedDateTime.java
+++ b/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/AttributedDateTime.java
@@ -17,10 +17,11 @@
 
 package org.opensaml.soap.wssecurity;
 
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
-import org.joda.time.format.DateTimeFormatter;
 import org.opensaml.core.xml.AttributeExtensibleXMLObject;
 import org.opensaml.core.xml.schema.XSString;
 
@@ -37,21 +38,12 @@ public interface AttributedDateTime extends XSString, IdBearing, AttributeExtens
     public static final QName TYPE_NAME = 
         new QName(WSSecurityConstants.WSU_NS, TYPE_LOCAL_NAME, WSSecurityConstants.WSU_PREFIX);
     
-    /** Default DateTime format. 
-     * 
-     * @deprecated replaced by use of a {@link DateTimeFormatter} 
-     *              configured via {@link #setDateTimeFormatter(DateTimeFormatter)}.
-     * 
-     */
-    @Deprecated
-    public static final String DEFAULT_DATETIME_FORMAT= "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
-
     /**
      * Returns the DateTime content or attribute value.
      * 
      * @return the {@link DateTime} object.
      */
-    public DateTime getDateTime();
+    public Instant getDateTime();
 
     /**
      * Sets the DateTime content or attribute value.
@@ -59,7 +51,7 @@ public interface AttributedDateTime extends XSString, IdBearing, AttributeExtens
      * @param dateTime
      *            the {@link DateTime} object to set.
      */
-    public void setDateTime(DateTime dateTime);
+    public void setDateTime(Instant dateTime);
     
     /**
      * Get the {@link DateTimeFormatter} to be used when stringifying
diff --git a/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/messaging/WSSecurityContext.java b/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/messaging/WSSecurityContext.java
index adf5c25..bbc5d4b 100644
--- a/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/messaging/WSSecurityContext.java
+++ b/opensaml-soap-api/src/main/java/org/opensaml/soap/wssecurity/messaging/WSSecurityContext.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.soap.wssecurity.messaging;
 
+import java.time.Instant;
 import java.util.List;
 
 import javax.annotation.Nonnull;
@@ -24,13 +25,12 @@ import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.collection.LazyList;
 
-import org.joda.time.DateTime;
 import org.opensaml.messaging.context.BaseContext;
 
 /**
  * A subcontext that carries information related to WS-Security processing.
  */
-public class WSSecurityContext extends BaseContext {
+public final class WSSecurityContext extends BaseContext {
     
     //TODO implement support for remaining items of WS-Security data model
     
@@ -38,10 +38,10 @@ public class WSSecurityContext extends BaseContext {
     private LazyList<Token> tokens;
     
     /** Value for Timestamp Created. */
-    private DateTime timestampCreated;
+    private Instant timestampCreated;
  
     /** Value for Timestamp Expires. */
-    private DateTime timestampExpires;
+    private Instant timestampExpires;
     
     /** Constructor. */
     public WSSecurityContext() {
@@ -63,7 +63,7 @@ public class WSSecurityContext extends BaseContext {
      * 
      * @return the Timestamp Created value
      */
-    @Nullable public DateTime getTimestampCreated() {
+    @Nullable public Instant getTimestampCreated() {
         return timestampCreated;
     }
 
@@ -72,7 +72,7 @@ public class WSSecurityContext extends BaseContext {
      * 
      * @param value the Timestamp Created value
      */
-    public void setTimestampCreated(@Nullable final DateTime value) {
+    public void setTimestampCreated(@Nullable final Instant value) {
         timestampCreated = value;
     }
 
@@ -81,7 +81,7 @@ public class WSSecurityContext extends BaseContext {
      * 
      * @return the Timestamp Expires value
      */
-    @Nullable public DateTime getTimestampExpires() {
+    @Nullable public Instant getTimestampExpires() {
         return timestampExpires;
     }
 
@@ -90,7 +90,7 @@ public class WSSecurityContext extends BaseContext {
      * 
      * @param value the Timestamp Expires value
      */
-    public void setTimestampExpires(@Nullable final DateTime value) {
+    public void setTimestampExpires(@Nullable final Instant value) {
         timestampExpires = value;
     }
 
diff --git a/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/impl/AttributedDateTimeImpl.java b/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/impl/AttributedDateTimeImpl.java
index 9e4e85c..486b3f5 100644
--- a/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/impl/AttributedDateTimeImpl.java
+++ b/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/impl/AttributedDateTimeImpl.java
@@ -17,10 +17,9 @@
 
 package org.opensaml.soap.wssecurity.impl;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.ISODateTimeFormat;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+
 import org.opensaml.core.xml.util.AttributeMap;
 import org.opensaml.soap.wssecurity.AttributedDateTime;
 import org.opensaml.soap.wssecurity.IdBearing;
@@ -35,7 +34,7 @@ public class AttributedDateTimeImpl extends AbstractWSSecurityObject implements
     private DateTimeFormatter formatter;
 
     /** DateTime object. */
-    private DateTime dateTimeValue;
+    private Instant dateTimeValue;
 
     /** String dateTime representation. */
     private String stringValue;
@@ -56,19 +55,19 @@ public class AttributedDateTimeImpl extends AbstractWSSecurityObject implements
     public AttributedDateTimeImpl(final String namespaceURI, final String elementLocalName,
             final String namespacePrefix) {
         super(namespaceURI, elementLocalName, namespacePrefix);
-        formatter = ISODateTimeFormat.dateTime().withChronology(ISOChronology.getInstanceUTC());
+        formatter = DateTimeFormatter.ISO_INSTANT;
         unknownAttributes = new AttributeMap(this);
     }
 
     /** {@inheritDoc} */
-    public DateTime getDateTime() {
+    public Instant getDateTime() {
         return dateTimeValue;
     }
 
     /** {@inheritDoc} */
-    public void setDateTime(final DateTime newDateTime) {
+    public void setDateTime(final Instant newDateTime) {
         dateTimeValue = newDateTime;
-        final String formattedDateTime = formatter.print(dateTimeValue);
+        final String formattedDateTime = formatter.format(dateTimeValue);
         stringValue = prepareForAssignment(stringValue, formattedDateTime);
     }
 
@@ -79,7 +78,7 @@ public class AttributedDateTimeImpl extends AbstractWSSecurityObject implements
 
     /** {@inheritDoc} */
     public void setValue(final String newValue) {
-        dateTimeValue = new DateTime(newValue).withChronology(ISOChronology.getInstanceUTC());
+        dateTimeValue = Instant.from(formatter.parse(newValue));
         stringValue = prepareForAssignment(stringValue, newValue);
     }
 
@@ -116,4 +115,4 @@ public class AttributedDateTimeImpl extends AbstractWSSecurityObject implements
         setDateTime(getDateTime());
     }
 
-}
+}
\ No newline at end of file
diff --git a/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandler.java b/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandler.java
index 9bec43e..d27c907 100644
--- a/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandler.java
+++ b/opensaml-soap-impl/src/main/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandler.java
@@ -17,15 +17,16 @@
 
 package org.opensaml.soap.wssecurity.messaging.impl;
 
+import java.time.Instant;
+import java.util.function.Function;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.util.XMLObjectSupport;
 import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import org.opensaml.messaging.handler.MessageHandlerException;
 import org.opensaml.soap.messaging.AbstractHeaderGeneratingMessageHandler;
 import org.opensaml.soap.wssecurity.Created;
@@ -43,13 +44,13 @@ import org.slf4j.LoggerFactory;
 public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler {
     
     /** Logger. */
-    private Logger log = LoggerFactory.getLogger(AddTimestampHandler.class);
+    @Nonnull private Logger log = LoggerFactory.getLogger(AddTimestampHandler.class);
     
     /** Context lookup function for the Created time. */
-    private ContextDataLookupFunction<MessageContext, DateTime> createdLookup;
+    @Nullable private Function<MessageContext,Instant> createdLookup;
     
     /** Context lookup function for the Expires time. */
-    private ContextDataLookupFunction<MessageContext, DateTime> expiresLookup;
+    @Nullable private Function<MessageContext,Instant> expiresLookup;
     
     /** Flag indicating whether to use the current time as the Created time, if no value
      * is explicitly supplied by the other supported mechanisms. */
@@ -60,17 +61,17 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
     private Long expiresOffsetFromCreated;
     
     /** The effective Created value to use. */
-    private DateTime createdValue;
+    private Instant createdValue;
     
     /** The effective Expires value to use. */
-    private DateTime expiresValue;
+    private Instant expiresValue;
     
     /**
      * Get the context lookup function for the Created time.
      * 
      * @return the lookup function
      */
-    @Nullable public ContextDataLookupFunction<MessageContext, DateTime> getCreatedLookup() {
+    @Nullable public Function<MessageContext,Instant> getCreatedLookup() {
         return createdLookup;
     }
 
@@ -79,7 +80,7 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
      * 
      * @param lookup the lookup function
      */
-    public void setCreatedLookup(@Nullable final ContextDataLookupFunction<MessageContext, DateTime> lookup) {
+    public void setCreatedLookup(@Nullable final Function<MessageContext,Instant> lookup) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         createdLookup = lookup;
@@ -90,7 +91,7 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
      * 
      * @return the lookup function
      */
-    @Nullable public ContextDataLookupFunction<MessageContext, DateTime> getExpiresLookup() {
+    @Nullable public Function<MessageContext,Instant> getExpiresLookup() {
         return expiresLookup;
     }
 
@@ -99,7 +100,7 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
      * 
      * @param lookup the lookup function
      */
-    public void setExpiresLookup(@Nullable final ContextDataLookupFunction<MessageContext, DateTime> lookup) {
+    public void setExpiresLookup(@Nullable final Function<MessageContext,Instant> lookup) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         expiresLookup = lookup;
@@ -194,8 +195,8 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
      * 
      * @return the effective Created DateTime value to use
      */
-    @Nullable protected DateTime getCreatedValue(@Nonnull final MessageContext messageContext) {
-        DateTime value = null;
+    @Nullable protected Instant getCreatedValue(@Nonnull final MessageContext messageContext) {
+        Instant value = null;
         final WSSecurityContext security = messageContext.getSubcontext(WSSecurityContext.class, false);
         if (security != null) {
             value = security.getTimestampCreated();
@@ -207,7 +208,7 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
         
         if (value == null) {
             if (isUseCurrentTimeAsDefaultCreated()) {
-                value = new DateTime();
+                value = Instant.now();
             }
         }
         return value;
@@ -221,9 +222,9 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
      * 
      * @return the effective Expires DateTime value to use
      */
-    @Nullable protected DateTime getExpiresValue(@Nonnull final MessageContext messageContext, 
-            @Nullable final DateTime created) {
-        DateTime value = null;
+    @Nullable protected Instant getExpiresValue(@Nonnull final MessageContext messageContext, 
+            @Nullable final Instant created) {
+        Instant value = null;
         final WSSecurityContext security = messageContext.getSubcontext(WSSecurityContext.class, false);
         if (security != null) {
             value = security.getTimestampExpires();
@@ -235,7 +236,7 @@ public class AddTimestampHandler extends AbstractHeaderGeneratingMessageHandler
         
         if (value == null) {
             if (getExpiresOffsetFromCreated() != null && created != null) {
-                return created.plus(getExpiresOffsetFromCreated());
+                return created.plusMillis(getExpiresOffsetFromCreated());
             }
         }
         return value;
diff --git a/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/impl/WSSecurityObjectsTestCase.java b/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/impl/WSSecurityObjectsTestCase.java
index f624563..957cffd 100644
--- a/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/impl/WSSecurityObjectsTestCase.java
+++ b/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/impl/WSSecurityObjectsTestCase.java
@@ -19,11 +19,13 @@ package org.opensaml.soap.wssecurity.impl;
 
 import org.testng.annotations.Test;
 import org.testng.Assert;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 import java.util.List;
 
 import org.custommonkey.xmlunit.Diff;
 import net.shibboleth.utilities.java.support.xml.XMLAssertTestNG;
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.io.Marshaller;
 import org.opensaml.soap.WSBaseTestCase;
@@ -172,12 +174,12 @@ public class WSSecurityObjectsTestCase extends WSBaseTestCase {
     public void testTimestamp() throws Exception {
         Timestamp timestamp= buildXMLObject(Timestamp.ELEMENT_NAME);
         Created created= buildXMLObject(Created.ELEMENT_NAME);
-        DateTime now= new DateTime();
+        Instant now= Instant.now();
         created.setDateTime(now);
         timestamp.setCreated(created);
 
         Expires expires= buildXMLObject(Expires.ELEMENT_NAME);
-        expires.setDateTime(now.plusMinutes(10));
+        expires.setDateTime(now.plus(10, ChronoUnit.MINUTES));
         timestamp.setExpires(expires);
 
         timestamp.setWSUId("Timestamp-" + System.currentTimeMillis());
@@ -204,7 +206,7 @@ public class WSSecurityObjectsTestCase extends WSBaseTestCase {
 
         UsernameToken usernameToken= createUsernameToken("test", "test");
         usernameToken.setWSUId(refId);
-        DateTime refDateTime= new DateTime(refDateTimeStr);
+        Instant refDateTime= Instant.parse(refDateTimeStr);
         Created usernameCreated = (Created) usernameToken.getUnknownXMLObjects(Created.ELEMENT_NAME).get(0);
         usernameCreated.setDateTime(refDateTime);
 
@@ -241,7 +243,7 @@ public class WSSecurityObjectsTestCase extends WSBaseTestCase {
         Assert.assertEquals(utPassword.getValue(), "test");
         Created utCreated = (Created) ut.getUnknownXMLObjects(Created.ELEMENT_NAME).get(0);
         Assert.assertNotNull(utCreated);
-        DateTime created= utCreated.getDateTime();
+        Instant created= utCreated.getDateTime();
         System.out.println(created);
 
     }
@@ -254,8 +256,7 @@ public class WSSecurityObjectsTestCase extends WSBaseTestCase {
         Password password= buildXMLObject(Password.ELEMENT_NAME);
         password.setValue(pass);
         Created created= buildXMLObject(Created.ELEMENT_NAME);
-        DateTime now= new DateTime();
-        created.setDateTime(now);
+        created.setDateTime(Instant.now());
 
         String id= "UsernameToken-" + System.currentTimeMillis();
         usernameToken.setWSUId(id);
diff --git a/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandlerTest.java b/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandlerTest.java
index 0d58a22..162d966 100644
--- a/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandlerTest.java
+++ b/opensaml-soap-impl/src/test/java/org/opensaml/soap/wssecurity/messaging/impl/AddTimestampHandlerTest.java
@@ -17,14 +17,12 @@
 
 package org.opensaml.soap.wssecurity.messaging.impl;
 
-import javax.annotation.Nullable;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
 
-import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
-import org.opensaml.messaging.context.MessageContext;
-import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import org.opensaml.messaging.handler.MessageHandlerException;
 import org.opensaml.soap.SOAPMessagingBaseTestCase;
 import org.opensaml.soap.messaging.SOAPMessagingSupport;
@@ -71,13 +69,13 @@ public class AddTimestampHandlerTest extends SOAPMessagingBaseTestCase {
         Assert.assertNotNull(timestamp.getCreated());
         Assert.assertNotNull(timestamp.getCreated().getDateTime());
         Assert.assertNotNull(timestamp.getExpires());
-        Assert.assertEquals(timestamp.getExpires().getDateTime(), timestamp.getCreated().getDateTime().plus(5*60*1000));
+        Assert.assertEquals(timestamp.getExpires().getDateTime(), timestamp.getCreated().getDateTime().plusMillis(5*60*1000));
     }
     
     @Test
     public void testContextBothValues() throws ComponentInitializationException, MessageHandlerException {
-        DateTime created = new DateTime(ISOChronology.getInstanceUTC());
-        DateTime expires = created.plusMinutes(5);
+        Instant created = Instant.now();
+        Instant expires = created.plus(5, ChronoUnit.MINUTES);
         getMessageContext().getSubcontext(WSSecurityContext.class, true).setTimestampCreated(created);
         getMessageContext().getSubcontext(WSSecurityContext.class, true).setTimestampExpires(expires);
         
@@ -97,7 +95,7 @@ public class AddTimestampHandlerTest extends SOAPMessagingBaseTestCase {
     
     @Test
     public void testContextCreated() throws ComponentInitializationException, MessageHandlerException {
-        DateTime created = new DateTime(ISOChronology.getInstanceUTC());
+        Instant created = Instant.now();
         getMessageContext().getSubcontext(WSSecurityContext.class, true).setTimestampCreated(created);
         
         handler.initialize();
@@ -115,8 +113,8 @@ public class AddTimestampHandlerTest extends SOAPMessagingBaseTestCase {
     
     @Test
     public void testContextExpires() throws ComponentInitializationException, MessageHandlerException {
-        DateTime created = new DateTime(ISOChronology.getInstanceUTC());
-        DateTime expires = created.plusMinutes(5);
+        Instant created = Instant.now();
+        Instant expires = created.plus(5, ChronoUnit.MINUTES);
         getMessageContext().getSubcontext(WSSecurityContext.class, true).setTimestampExpires(expires);
         
         handler.initialize();
@@ -134,8 +132,8 @@ public class AddTimestampHandlerTest extends SOAPMessagingBaseTestCase {
     
     @Test
     public void testContextCreatedWithOffset() throws ComponentInitializationException, MessageHandlerException {
-        DateTime created = new DateTime(ISOChronology.getInstanceUTC());
-        DateTime expires = created.plusMinutes(5);
+        Instant created = Instant.now();
+        Instant expires = created.plus(5, ChronoUnit.MINUTES);
         getMessageContext().getSubcontext(WSSecurityContext.class, true).setTimestampCreated(created);
         handler.setExpiresOffsetFromCreated(5*60*1000L);
         
@@ -155,18 +153,10 @@ public class AddTimestampHandlerTest extends SOAPMessagingBaseTestCase {
     
     @Test
     public void testLookupBothValues() throws ComponentInitializationException, MessageHandlerException {
-        final DateTime created = new DateTime(ISOChronology.getInstanceUTC());
-        final DateTime expires = created.plusMinutes(5);
-        handler.setCreatedLookup(new ContextDataLookupFunction<MessageContext, DateTime>() {
-            @Nullable public DateTime apply(@Nullable MessageContext input) {
-                return created;
-            }
-        });
-        handler.setExpiresLookup(new ContextDataLookupFunction<MessageContext, DateTime>() {
-            @Nullable public DateTime apply(@Nullable MessageContext input) {
-                return expires;
-            }
-        });
+        Instant created = Instant.now();
+        Instant expires = created.plus(5, ChronoUnit.MINUTES);
+        handler.setCreatedLookup(FunctionSupport.constant(created));
+        handler.setExpiresLookup(FunctionSupport.constant(expires));
         
         handler.initialize();
         handler.invoke(getMessageContext());
@@ -184,13 +174,9 @@ public class AddTimestampHandlerTest extends SOAPMessagingBaseTestCase {
     
     @Test
     public void testLookupCreatedWithOffset() throws ComponentInitializationException, MessageHandlerException {
-        final DateTime created = new DateTime(ISOChronology.getInstanceUTC());
-        final DateTime expires = created.plusMinutes(5);
-        handler.setCreatedLookup(new ContextDataLookupFunction<MessageContext, DateTime>() {
-            @Nullable public DateTime apply(@Nullable MessageContext input) {
-                return created;
-            }
-        });
+        Instant created = Instant.now();
+        Instant expires = created.plus(5, ChronoUnit.MINUTES);
+        handler.setCreatedLookup(FunctionSupport.constant(created));
         handler.setExpiresOffsetFromCreated(5*60*1000L);
         
         
diff --git a/opensaml-soap-impl/src/test/java/org/opensaml/soap/wstrust/impl/WSTrustObjectsTestCase.java b/opensaml-soap-impl/src/test/java/org/opensaml/soap/wstrust/impl/WSTrustObjectsTestCase.java
index 55e9f30..89996a8 100644
--- a/opensaml-soap-impl/src/test/java/org/opensaml/soap/wstrust/impl/WSTrustObjectsTestCase.java
+++ b/opensaml-soap-impl/src/test/java/org/opensaml/soap/wstrust/impl/WSTrustObjectsTestCase.java
@@ -20,9 +20,11 @@ package org.opensaml.soap.wstrust.impl;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
+
+import java.time.Instant;
+
 import javax.xml.namespace.QName;
 
-import org.joda.time.DateTime;
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.core.xml.schema.XSAny;
 import org.opensaml.core.xml.schema.XSBooleanValue;
@@ -415,7 +417,7 @@ public class WSTrustObjectsTestCase extends WSBaseTestCase {
     protected Timestamp createTimestamp() throws Exception {
         Timestamp timestamp= buildXMLObject(Timestamp.ELEMENT_NAME);
         Created created= buildXMLObject(Created.ELEMENT_NAME);
-        created.setDateTime(new DateTime());
+        created.setDateTime(Instant.now());
         timestamp.setCreated(created);
         return timestamp;
     }
@@ -439,7 +441,7 @@ public class WSTrustObjectsTestCase extends WSBaseTestCase {
         Password password= buildXMLObject(Password.ELEMENT_NAME);
         password.setValue(pass);
         Created created= buildXMLObject(Created.ELEMENT_NAME);
-        created.setDateTime(new DateTime());
+        created.setDateTime(Instant.now());
         String id= "UsernameToken-" + System.currentTimeMillis();
         usernameToken.setWSUId(id);
         usernameToken.setUsername(username);
diff --git a/opensaml-storage-api/pom.xml b/opensaml-storage-api/pom.xml
index c9debb4..6f818e6 100644
--- a/opensaml-storage-api/pom.xml
+++ b/opensaml-storage-api/pom.xml
@@ -22,10 +22,6 @@
 
     <dependencies>
         <!-- Compile Dependencies -->
-        <dependency>
-            <groupId>joda-time</groupId>
-            <artifactId>joda-time</artifactId>
-        </dependency>
 
         <!-- Provided Dependencies -->
 
diff --git a/opensaml-storage-api/src/main/java/org/opensaml/storage/annotation/AnnotationSupport.java b/opensaml-storage-api/src/main/java/org/opensaml/storage/annotation/AnnotationSupport.java
index 0b877b1..b27bbba 100644
--- a/opensaml-storage-api/src/main/java/org/opensaml/storage/annotation/AnnotationSupport.java
+++ b/opensaml-storage-api/src/main/java/org/opensaml/storage/annotation/AnnotationSupport.java
@@ -19,6 +19,7 @@ package org.opensaml.storage.annotation;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.time.Instant;
 import java.util.Date;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -28,9 +29,6 @@ import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 
-import org.joda.time.Instant;
-import org.joda.time.ReadableInstant;
-
 /**
  * Support class that reads and writes fields decorated with storage annotations.
  */
@@ -180,8 +178,8 @@ public final class AnnotationSupport {
             return (Long) value;
         } else if (value instanceof Date) {
             return ((Date) value).getTime();
-        } else if (value instanceof ReadableInstant) {
-            return ((ReadableInstant) value).getMillis();
+        } else if (value instanceof Instant) {
+            return ((Instant) value).toEpochMilli();
         }
         throw new RuntimeException(value + " is an unsupported data type for an expiration field.");
     }
@@ -215,8 +213,8 @@ public final class AnnotationSupport {
             setFieldValue(target, expField.value(), expiration);
         } else if (Date.class.isAssignableFrom(type)) {
             setFieldValue(target, expField.value(), new Date(expiration));
-        } else if (ReadableInstant.class.isAssignableFrom(type)) {
-            setFieldValue(target, expField.value(), new Instant(expiration));
+        } else if (Instant.class.isAssignableFrom(type)) {
+            setFieldValue(target, expField.value(), Instant.ofEpochMilli(expiration));
         } else {
             throw new RuntimeException(type + " is an unsupported data type for an expiration field.");
         }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list