killbill-aplcache

Merge branch 'work-for-release-0.17.0' of github.com:killbill/killbill

2/17/2016 6:53:18 PM

Changes

Details

diff --git a/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java b/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
index ca0cd0c..bc78b08 100644
--- a/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
+++ b/api/src/main/java/org/killbill/billing/callcontext/InternalCallContext.java
@@ -63,8 +63,8 @@ public class InternalCallContext extends InternalTenantContext {
         this.contextUserType = userType;
         this.reasonCode = reasonCode;
         this.comments = comment;
-        this.createdDate = toUTCDateTime(createdDate);
-        this.updatedDate = toUTCDateTime(updatedDate);
+        this.createdDate = createdDate;
+        this.updatedDate = updatedDate;
     }
 
     public InternalCallContext(final Long tenantRecordId, final CallContext callContext, final DateTime utcNow) {
diff --git a/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java b/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
index c5c88e9..89f710c 100644
--- a/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
+++ b/api/src/main/java/org/killbill/billing/callcontext/TimeAwareContext.java
@@ -23,6 +23,7 @@ import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.joda.time.LocalTime;
+import org.killbill.clock.ClockUtil;
 
 public class TimeAwareContext {
 
@@ -34,41 +35,16 @@ public class TimeAwareContext {
         this.referenceTime = computeReferenceTime(referenceDateTime);
     }
 
-    /// Generic functions
-    /// TODO Move to ClockUtil
-
-    // Create a DateTime object forcing the time zone to be UTC
-    protected DateTime toUTCDateTime(final DateTime dateTime) {
-        return toDateTime(dateTime, DateTimeZone.UTC);
-    }
-
-    // Create a DateTime object using the specified timezone (usually, the one on the account)
-    public DateTime toDateTime(final DateTime dateTime, final DateTimeZone accountTimeZone) {
-        return dateTime.toDateTime(accountTimeZone);
-    }
-
-    /// DateTime <-> LocalDate transformations
-
-    // Create a DateTime object using the specified reference time and timezone (usually, the one on the account)
     public DateTime toUTCDateTime(final LocalDate localDate) {
         validateContext();
 
-        final DateTime targetDateTime = new DateTime(localDate.getYear(),
-                                                     localDate.getMonthOfYear(),
-                                                     localDate.getDayOfMonth(),
-                                                     getReferenceTime().getHourOfDay(),
-                                                     getReferenceTime().getMinuteOfHour(),
-                                                     getReferenceTime().getSecondOfMinute(),
-                                                     getFixedOffsetTimeZone());
-
-        return toUTCDateTime(targetDateTime);
+        return ClockUtil.toUTCDateTime(localDate, getReferenceTime(), getFixedOffsetTimeZone());
     }
 
-    // Create a LocalDate object using the specified timezone (usually, the one on the account), respecting the offset at the time of the referenceDateTime
     public LocalDate toLocalDate(final DateTime dateTime) {
         validateContext();
 
-        return new LocalDate(dateTime, getFixedOffsetTimeZone());
+        return ClockUtil.toLocalDate(dateTime, getFixedOffsetTimeZone());
     }
 
     private void validateContext() {
@@ -77,16 +53,19 @@ public class TimeAwareContext {
         }
     }
 
+    // For convenience (used in tests)
+
+    //@VisibleForTesting
     protected LocalTime computeReferenceTime(@Nullable final DateTime referenceTime) {
-        return referenceTime == null ? null : toDateTime(referenceTime, getFixedOffsetTimeZone()).toLocalTime();
+        return referenceTime == null ? null : ClockUtil.toDateTime(referenceTime, getFixedOffsetTimeZone()).toLocalTime();
     }
 
-    // For convenience, to be overridden in tests
-
+    //@VisibleForTesting
     public DateTimeZone getFixedOffsetTimeZone() {
         return fixedOffsetTimeZone;
     }
 
+    //@VisibleForTesting
     public LocalTime getReferenceTime() {
         return referenceTime;
     }
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
index d8fca92..5f0149c 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegration.java
@@ -78,7 +78,7 @@ public class TestIntegration extends TestIntegrationBase {
         //
 
         TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
-                                                             SubscriptionEventType.START_BILLING, null, null, clock.getUTCNow(), null);
+                                                             SubscriptionEventType.START_BILLING, null, null, null, null);
         Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
@@ -93,7 +93,7 @@ public class TestIntegration extends TestIntegrationBase {
         // ADD ADD_ON ON THE SAME DAY
         //
         dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, null, null,
-                                         SubscriptionEventType.START_BILLING, null, bpSubscription.getBundleId(), clock.getUTCNow(), null);
+                                         SubscriptionEventType.START_BILLING, null, bpSubscription.getBundleId(), null, null);
         dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("399.95")));
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
@@ -109,7 +109,7 @@ public class TestIntegration extends TestIntegrationBase {
         // There is no invoice created as we only adjust the previous invoice.
         //
         dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, null, null, null, null, null, SubscriptionEventType.STOP_BILLING, bpSubscription.getId(),
-                                         bpSubscription.getBundleId(), clock.getUTCNow(), null);
+                                         bpSubscription.getBundleId(), null, null);
         dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2012, 4, 1), new LocalDate(2012, 5, 1), InvoiceItemType.REPAIR_ADJ, new BigDecimal("-399.95")));
         // The second invoice should be adjusted for the AO (we paid for the full period) and since we paid we should also see a CBA
@@ -153,7 +153,7 @@ public class TestIntegration extends TestIntegrationBase {
         // CHANGE PLAN IMMEDIATELY AND EXPECT BOTH EVENTS: NextEvent.CHANGE NextEvent.INVOICE
         //
         TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null, SubscriptionEventType.CHANGE,
-                                                             subscription.getId(), subscription.getBundleId(), clock.getUTCNow(), null);
+                                                             subscription.getId(), subscription.getBundleId(), null, null);
         Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(initialCreationDate.toLocalDate(), null, InvoiceItemType.FIXED, new BigDecimal("0")));
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
index caff3d5..3a7e621 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestIntegrationBase.java
@@ -99,10 +99,7 @@ import org.killbill.billing.util.api.RecordIdApi;
 import org.killbill.billing.util.api.TagApiException;
 import org.killbill.billing.util.api.TagDefinitionApiException;
 import org.killbill.billing.util.api.TagUserApi;
-import org.killbill.billing.util.cache.Cachable.CacheType;
 import org.killbill.billing.util.cache.CacheControllerDispatcher;
-import org.killbill.billing.util.callcontext.CallContext;
-import org.killbill.billing.util.callcontext.TestCallContext;
 import org.killbill.billing.util.dao.NonEntityDao;
 import org.killbill.billing.util.nodes.KillbillNodesApi;
 import org.killbill.billing.util.tag.ControlTagType;
@@ -434,7 +431,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                     final PluginProperty prop1 = new PluginProperty(InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID, invoice.getId().toString(), false);
                     properties.add(prop1);
                     return paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, amount, currency, UUID.randomUUID().toString(),
-                                                                       UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, refreshedCallContext());
+                                                                       UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, callContext);
                 } catch (final PaymentApiException e) {
                     fail(e.toString());
                     return null;
@@ -453,7 +450,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                     properties.add(prop1);
 
                     return paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, invoice.getBalance(), invoice.getCurrency(), UUID.randomUUID().toString(),
-                                                                       UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, refreshedCallContext());
+                                                                       UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, callContext);
                 } catch (final PaymentApiException e) {
                     fail(e.toString());
                     return null;
@@ -473,7 +470,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                     properties.add(prop1);
 
                     return paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, invoice.getBalance(), invoice.getCurrency(), UUID.randomUUID().toString(),
-                                                                       UUID.randomUUID().toString(), properties, EXTERNAL_PAYMENT_OPTIONS, refreshedCallContext());
+                                                                       UUID.randomUUID().toString(), properties, EXTERNAL_PAYMENT_OPTIONS, callContext);
                 } catch (final PaymentApiException e) {
                     fail(e.toString());
                     return null;
@@ -492,7 +489,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
             public Payment apply(@Nullable final Void input) {
                 try {
                     return paymentApi.createRefundWithPaymentControl(account, payment.getId(), amount, currency, UUID.randomUUID().toString(),
-                                                                     PLUGIN_PROPERTIES, PAYMENT_OPTIONS, refreshedCallContext());
+                                                                     PLUGIN_PROPERTIES, PAYMENT_OPTIONS, callContext);
                 } catch (final PaymentApiException e) {
                     fail(e.toString());
                     return null;
@@ -511,7 +508,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                 properties.add(prop1);
                 try {
                     return paymentApi.createRefundWithPaymentControl(account, payment.getId(), payment.getPurchasedAmount(), payment.getCurrency(), UUID.randomUUID().toString(),
-                                                                     properties, PAYMENT_OPTIONS, refreshedCallContext());
+                                                                     properties, PAYMENT_OPTIONS, callContext);
                 } catch (final PaymentApiException e) {
                     fail(e.toString());
                     return null;
@@ -536,7 +533,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
 
                 try {
                     return paymentApi.createRefundWithPaymentControl(account, payment.getId(), amount, currency, UUID.randomUUID().toString(),
-                                                                     properties, PAYMENT_OPTIONS, refreshedCallContext());
+                                                                     properties, PAYMENT_OPTIONS, callContext);
                 } catch (final PaymentApiException e) {
                     fail(e.toString());
                     return null;
@@ -555,7 +552,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
             public Payment apply(@Nullable final Void input) {
                 try {
                     return paymentApi.createChargebackWithPaymentControl(account, payment.getId(), amount, currency, UUID.randomUUID().toString(),
-                                                                         PAYMENT_OPTIONS, refreshedCallContext());
+                                                                         PAYMENT_OPTIONS, callContext);
                 } catch (final PaymentApiException e) {
                     fail(e.toString());
                     return null;
@@ -729,11 +726,6 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         assertListenerStatus();
     }
 
-    // Update the context dates (matters for payments ordering for instance)
-    protected CallContext refreshedCallContext() {
-        return new TestCallContext(callContext, clock.getUTCNow());
-    }
-
     private <T> T doCallAndCheckForCompletion(final Function<Void, T> f, final NextEvent... events) {
         final Joiner joiner = Joiner.on(", ");
         log.debug("            ************    STARTING BUS HANDLER CHECK : {} ********************", joiner.join(events));
@@ -754,7 +746,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         private final SubscriptionEventType action;
         private final UUID subscriptionId;
         private final UUID bundleId;
-        private final DateTime effectiveDate;
+        private final LocalDate effectiveDate;
         private final BillingActionPolicy billingPolicy;
 
         public TestDryRunArguments(final DryRunType dryRunType) {
@@ -776,7 +768,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
                                    final SubscriptionEventType action,
                                    final UUID subscriptionId,
                                    final UUID bundleId,
-                                   final DateTime effectiveDate,
+                                   final LocalDate effectiveDate,
                                    final BillingActionPolicy billingPolicy) {
             this.dryRunType = dryRunType;
             this.spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceList, phaseType);
@@ -808,7 +800,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB {
         }
 
         @Override
-        public DateTime getEffectiveDate() {
+        public LocalDate getEffectiveDate() {
             return effectiveDate;
         }
 
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
index e3bb373..5894656 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestWithTimeZones.java
@@ -24,6 +24,7 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.joda.time.IllegalInstantException;
 import org.joda.time.LocalDate;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountData;
@@ -75,7 +76,7 @@ public class TestWithTimeZones extends TestIntegrationBase {
         final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
 
         final TestDryRunArguments dryRun = new TestDryRunArguments(DryRunType.SUBSCRIPTION_ACTION, "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, null, null,
-                                                                   SubscriptionEventType.START_BILLING, null, null, clock.getUTCNow(), null);
+                                                                   SubscriptionEventType.START_BILLING, null, null, null, null);
         final Invoice dryRunInvoice = invoiceUserApi.triggerInvoiceGeneration(account.getId(), clock.getUTCToday(), dryRun, callContext);
         expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2015, 9, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
         invoiceChecker.checkInvoiceNoAudits(dryRunInvoice, callContext, expectedInvoices);
@@ -197,4 +198,60 @@ public class TestWithTimeZones extends TestIntegrationBase {
         final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(account.getId(), callContext);
         Assert.assertEquals(invoices.size(), 1);
     }
+
+    @Test(groups = "slow")
+    public void testReferenceTimeInDSTGap() throws Exception {
+        final DateTimeZone tz = DateTimeZone.forID("America/Los_Angeles");
+        clock.setTime(new DateTime(2015, 3, 7, 2, 0, 0, tz));
+
+        final AccountData accountData = new MockAccountBuilder().currency(Currency.USD)
+                                                                .timeZone(tz)
+                                                                .build();
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+        accountChecker.checkAccount(account.getId(), accountData, callContext);
+        Assert.assertEquals(account.getTimeZone(), tz);
+        Assert.assertEquals(account.getFixedOffsetTimeZone(), DateTimeZone.forOffsetHours(-8));
+
+        // Note the gap: 2015-03-07T02:00:00.000-08:00 to 2015-03-08T03:00:00.000-07:00
+        clock.addDays(1);
+
+        try {
+            // See TimeAwareContext#toUTCDateTime (which uses account.getFixedOffsetTimeZone() instead)
+            new DateTime(clock.getUTCToday().getYear(),
+                         clock.getUTCToday().getMonthOfYear(),
+                         clock.getUTCToday().getDayOfMonth(),
+                         account.getReferenceTime().toDateTime(tz).getHourOfDay(),
+                         account.getReferenceTime().toDateTime(tz).getMinuteOfHour(),
+                         account.getReferenceTime().toDateTime(tz).getSecondOfMinute(),
+                         account.getTimeZone());
+            Assert.fail();
+        } catch (final IllegalInstantException e) {
+            // Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-08T10:00:00.000 (America/Los_Angeles)
+        }
+
+        busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Blowdart", ProductCategory.BASE, BillingPeriod.MONTHLY, "notrial", null);
+        // Pass a date of today, to trigger TimeAwareContext#toUTCDateTime
+        final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, "Something", ImmutableList.<PlanPhasePriceOverride>of(), clock.getUTCToday(), ImmutableList.<PluginProperty>of(), callContext);
+        assertListenerStatus();
+
+        Assert.assertEquals(entitlement.getEffectiveStartDate().compareTo(new LocalDate("2015-03-08")), 0);
+        Assert.assertEquals(((DefaultEntitlement) entitlement).getBasePlanSubscriptionBase().getStartDate().compareTo(new DateTime("2015-03-08T02:00:00.000-08:00")), 0);
+
+        invoiceChecker.checkChargedThroughDate(entitlement.getId(), new LocalDate("2015-04-08"), callContext);
+
+        busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        clock.addDays(31);
+        assertListenerStatus();
+
+        invoiceChecker.checkChargedThroughDate(entitlement.getId(), new LocalDate("2015-05-08"), callContext);
+
+        for (int i = 0; i < 25 ; i++) {
+            busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+            clock.addMonths(1);
+            assertListenerStatus();
+
+            invoiceChecker.checkChargedThroughDate(entitlement.getId(), new LocalDate("2015-03-08").plusMonths(3 + i), callContext);
+        }
+    }
 }
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
index 71fa477..07ddabf 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestEntitlementDateHelper.java
@@ -138,6 +138,7 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
                                                      accountInternalApi,
                                                      immutableAccountInternalApi,
                                                      nonEntityDao,
+                                                     clock,
                                                      internalCallContextFactory,
                                                      callContext,
                                                      internalCallContext);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
index 5e43715..8b41884 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/engine/core/TestEntitlementUtils.java
@@ -26,22 +26,14 @@ import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
-import org.killbill.billing.ObjectType;
-import org.killbill.billing.entitlement.AccountEventsStreams;
-import org.killbill.billing.payment.api.PluginProperty;
-import org.killbill.billing.util.cache.Cachable.CacheType;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.api.TestApiListener.NextEvent;
-import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
 import org.killbill.billing.catalog.api.PriceListSet;
 import org.killbill.billing.catalog.api.ProductCategory;
+import org.killbill.billing.entitlement.AccountEventsStreams;
 import org.killbill.billing.entitlement.EntitlementService;
 import org.killbill.billing.entitlement.EntitlementTestSuiteWithEmbeddedDB;
 import org.killbill.billing.entitlement.EventsStream;
@@ -52,7 +44,10 @@ import org.killbill.billing.entitlement.api.DefaultEntitlementApi;
 import org.killbill.billing.entitlement.api.Entitlement;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
 import org.killbill.billing.entitlement.api.EntitlementApiException;
-import org.killbill.billing.entitlement.dao.BlockingStateSqlDao;
+import org.killbill.billing.payment.api.PluginProperty;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
@@ -61,8 +56,6 @@ import com.google.common.collect.Iterables;
 
 public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
 
-    private BlockingStateSqlDao sqlDao;
-    private Account account;
     private DefaultEntitlement baseEntitlement;
     private DefaultEntitlement addOnEntitlement;
     // Dates for the base plan only
@@ -73,10 +66,8 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
 
     @BeforeMethod(groups = "slow")
     public void setUp() throws Exception {
-        sqlDao = dbi.onDemand(BlockingStateSqlDao.class);
-
         clock.setDay(initialDate);
-        account = createAccount(getAccountData(7));
+        final Account account = createAccount(getAccountData(7));
 
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.CREATE);
 
@@ -452,7 +443,6 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
     }
 
     private Collection<BlockingState> computeFutureBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement) throws EntitlementApiException {
-        setContextAccountRecordId();
         final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(internalCallContext);
 
         final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(accountEventsStreams.getEventsStreams().values()),
@@ -471,7 +461,6 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
     }
 
     private Collection<BlockingState> computeBlockingStatesForAssociatedAddonsViaAccount(final DefaultEntitlement baseEntitlement, final DateTime effectiveDate) throws EntitlementApiException {
-        setContextAccountRecordId();
         final AccountEventsStreams accountEventsStreams = eventsStreamBuilder.buildForAccount(internalCallContext);
 
         final EventsStream eventsStream = Iterables.<EventsStream>find(Iterables.<EventsStream>concat(accountEventsStreams.getEventsStreams().values()),
@@ -493,8 +482,4 @@ public class TestEntitlementUtils extends EntitlementTestSuiteWithEmbeddedDB {
                                                                                        }
                                                                                    }));
     }
-
-    private void setContextAccountRecordId() {
-        internalCallContext.setAccountRecordId(nonEntityDao.retrieveRecordIdFromObject(account.getId(), ObjectType.ACCOUNT, controlCacheDispatcher.getCacheController(CacheType.RECORD_ID)));
-    }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
index 9f0e176..f4fac61 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/api/user/DefaultInvoiceUserApi.java
@@ -28,14 +28,12 @@ import java.util.UUID;
 
 import javax.annotation.Nullable;
 
-import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
-import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.Currency;
@@ -208,15 +206,7 @@ public class DefaultInvoiceUserApi implements InvoiceUserApi {
                                             final CallContext context) throws InvoiceApiException {
         final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(accountId, context);
 
-        final ImmutableAccountData account;
-        try {
-            account = accountUserApi.getImmutableAccountDataById(accountId, internalContext);
-        } catch (final AccountApiException e) {
-            throw new InvoiceApiException(e, ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, e.toString());
-        }
-
-        final DateTime processingDateTime = targetDate != null ? targetDate.toDateTimeAtCurrentTime(account.getTimeZone()) : null;
-        final Invoice result = dispatcher.processAccount(accountId, processingDateTime, dryRunArguments, internalContext);
+        final Invoice result = dispatcher.processAccount(accountId, targetDate, dryRunArguments, internalContext);
         if (result == null) {
             throw new InvoiceApiException(ErrorCode.INVOICE_NOTHING_TO_DO, accountId, targetDate != null ? targetDate : "null");
         } else {
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
index a9e4d02..b3db9fd 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceDispatcher.java
@@ -108,6 +108,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
 import com.google.inject.Inject;
 
@@ -165,19 +166,19 @@ public class InvoiceDispatcher {
     public void processSubscriptionForInvoiceGeneration(final EffectiveSubscriptionInternalEvent transition,
                                                         final InternalCallContext context) throws InvoiceApiException {
         final UUID subscriptionId = transition.getSubscriptionId();
-        final DateTime targetDate = transition.getEffectiveTransitionTime();
+        final LocalDate targetDate = context.toLocalDate(transition.getEffectiveTransitionTime());
         processSubscriptionForInvoiceGeneration(subscriptionId, targetDate, context);
     }
 
-    public void processSubscriptionForInvoiceGeneration(final UUID subscriptionId, final DateTime targetDate, final InternalCallContext context) throws InvoiceApiException {
+    public void processSubscriptionForInvoiceGeneration(final UUID subscriptionId, final LocalDate targetDate, final InternalCallContext context) throws InvoiceApiException {
         processSubscriptionInternal(subscriptionId, targetDate, false, context);
     }
 
-    public void processSubscriptionForInvoiceNotification(final UUID subscriptionId, final DateTime targetDate, final InternalCallContext context) throws InvoiceApiException {
+    public void processSubscriptionForInvoiceNotification(final UUID subscriptionId, final LocalDate targetDate, final InternalCallContext context) throws InvoiceApiException {
         final Invoice dryRunInvoice = processSubscriptionInternal(subscriptionId, targetDate, true, context);
         if (dryRunInvoice != null && dryRunInvoice.getBalance().compareTo(BigDecimal.ZERO) > 0) {
             final InvoiceNotificationInternalEvent event = new DefaultInvoiceNotificationInternalEvent(dryRunInvoice.getAccountId(), dryRunInvoice.getBalance(), dryRunInvoice.getCurrency(),
-                                                                                                       targetDate, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
+                                                                                                       context.toUTCDateTime(targetDate), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
             try {
                 eventBus.post(event);
             } catch (final EventBusException e) {
@@ -186,7 +187,7 @@ public class InvoiceDispatcher {
         }
     }
 
-    private Invoice processSubscriptionInternal(final UUID subscriptionId, final DateTime targetDate, final boolean dryRunForNotification, final InternalCallContext context) throws InvoiceApiException {
+    private Invoice processSubscriptionInternal(final UUID subscriptionId, final LocalDate targetDate, final boolean dryRunForNotification, final InternalCallContext context) throws InvoiceApiException {
         try {
             if (subscriptionId == null) {
                 log.error("Failed handling SubscriptionBase change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
@@ -203,7 +204,7 @@ public class InvoiceDispatcher {
         }
     }
 
-    public Invoice processAccount(final UUID accountId, @Nullable final DateTime targetDate,
+    public Invoice processAccount(final UUID accountId, @Nullable final LocalDate targetDate,
                                   @Nullable final DryRunArguments dryRunArguments, final InternalCallContext context) throws InvoiceApiException {
         GlobalLock lock = null;
         try {
@@ -222,13 +223,18 @@ public class InvoiceDispatcher {
         return null;
     }
 
-    private Invoice processAccountWithLock(final UUID accountId, @Nullable final DateTime inputTargetDateTime,
+    private Invoice processAccountWithLock(final UUID accountId, @Nullable final LocalDate inputTargetDateMaybeNull,
                                            @Nullable final DryRunArguments dryRunArguments, final InternalCallContext context) throws InvoiceApiException {
-
         final boolean isDryRun = dryRunArguments != null;
-        // A null inputTargetDateTime is only allowed in dryRun mode to have the system compute it
-        Preconditions.checkArgument(inputTargetDateTime != null ||
-                                    (dryRunArguments != null && DryRunType.UPCOMING_INVOICE.equals(dryRunArguments.getDryRunType())), "inputTargetDateTime is required in non dryRun mode");
+        final boolean upcomingInvoiceDryRun = isDryRun && DryRunType.UPCOMING_INVOICE.equals(dryRunArguments.getDryRunType());
+
+        LocalDate inputTargetDate = inputTargetDateMaybeNull;
+        // A null inputTargetDate is only allowed in dryRun mode to have the system compute it
+        if (inputTargetDate == null && !upcomingInvoiceDryRun) {
+            inputTargetDate = clock.getUTCToday();
+        }
+        Preconditions.checkArgument(inputTargetDate != null || upcomingInvoiceDryRun, "inputTargetDate is required in non dryRun mode");
+
         try {
             // Make sure to first set the BCD if needed then get the account object (to have the BCD set)
             final BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId, dryRunArguments, context);
@@ -236,11 +242,11 @@ public class InvoiceDispatcher {
                 return null;
             }
             final Iterable<UUID> filteredSubscriptionIdsForDryRun = getFilteredSubscriptionIdsForDryRun(dryRunArguments, billingEvents);
-            final List<DateTime> candidateDateTimes = (inputTargetDateTime != null) ?
-                                                      ImmutableList.of(inputTargetDateTime) :
-                                                      getUpcomingInvoiceCandidateDates(filteredSubscriptionIdsForDryRun, context);
-            for (final DateTime curTargetDateTime : candidateDateTimes) {
-                final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDateTime, billingEvents, isDryRun, context);
+            final List<LocalDate> candidateTargetDates = (inputTargetDate != null) ?
+                                                         ImmutableList.<LocalDate>of(inputTargetDate) :
+                                                         getUpcomingInvoiceCandidateDates(filteredSubscriptionIdsForDryRun, context);
+            for (final LocalDate curTargetDate : candidateTargetDates) {
+                final Invoice invoice = processAccountWithLockAndInputTargetDate(accountId, curTargetDate, billingEvents, isDryRun, context);
                 if (invoice != null) {
                     filterInvoiceItemsForDryRun(filteredSubscriptionIdsForDryRun, invoice);
                     return invoice;
@@ -294,7 +300,7 @@ public class InvoiceDispatcher {
         });
     }
 
-    private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final DateTime targetDateTime,
+    private Invoice processAccountWithLockAndInputTargetDate(final UUID accountId, final LocalDate targetDate,
                                                              final BillingEventSet billingEvents, final boolean isDryRun, final InternalCallContext context) throws InvoiceApiException {
         try {
             final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, context);
@@ -310,7 +316,6 @@ public class InvoiceDispatcher {
                                                                                                 }));
 
             final Currency targetCurrency = account.getCurrency();
-            final LocalDate targetDate = context.toLocalDate(targetDateTime);
             final InvoiceWithMetadata invoiceWithMetadata = generator.generateInvoice(account, billingEvents, invoices, targetDate, targetCurrency, context);
             final Invoice invoice = invoiceWithMetadata.getInvoice();
 
@@ -323,9 +328,9 @@ public class InvoiceDispatcher {
             //
             if (invoice == null) {
                 if (isDryRun) {
-                    log.info("Generated null dryRun invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
+                    log.info("Generated null dryRun invoice for accountId {} and targetDate {}", accountId, targetDate);
                 } else {
-                    log.info("Generated null invoice for accountId {} and targetDate {} (targetDateTime {})", new Object[]{accountId, targetDate, targetDateTime});
+                    log.info("Generated null invoice for accountId {} and targetDate {}", accountId, targetDate);
 
                     final BusInternalEvent event = new DefaultNullInvoiceEvent(accountId, clock.getUTCToday(),
                                                                                context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken());
@@ -610,11 +615,16 @@ public class InvoiceDispatcher {
         }
     }
 
-    private List<DateTime> getUpcomingInvoiceCandidateDates(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
+    private List<LocalDate> getUpcomingInvoiceCandidateDates(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
         final Iterable<DateTime> nextScheduledInvoiceDates = getNextScheduledInvoiceEffectiveDate(filteredSubscriptionIds, internalCallContext);
         final Iterable<DateTime> nextScheduledSubscriptionsEventDates = subscriptionApi.getFutureNotificationsForAccount(internalCallContext);
-        Iterables.concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates);
-        return UPCOMING_NOTIFICATION_DATE_ORDERING.sortedCopy(Iterables.concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates));
+        return Lists.<DateTime, LocalDate>transform(UPCOMING_NOTIFICATION_DATE_ORDERING.sortedCopy(Iterables.<DateTime>concat(nextScheduledInvoiceDates, nextScheduledSubscriptionsEventDates)),
+                                                    new Function<DateTime, LocalDate>() {
+                                                        @Override
+                                                        public LocalDate apply(final DateTime input) {
+                                                            return internalCallContext.toLocalDate(input);
+                                                        }
+                                                    });
     }
 
     private Iterable<DateTime> getNextScheduledInvoiceEffectiveDate(final Iterable<UUID> filteredSubscriptionIds, final InternalCallContext internalCallContext) {
@@ -669,7 +679,7 @@ public class InvoiceDispatcher {
         }
 
         @Override
-        public DateTime getEffectiveDate() {
+        public LocalDate getEffectiveDate() {
             return null;
         }
 
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
index 165f849..a9a128f 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceListener.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -30,8 +32,6 @@ import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.util.callcontext.CallOrigin;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.billing.util.config.InvoiceConfig;
-import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,27 +46,21 @@ public class InvoiceListener {
     private final InvoiceDispatcher dispatcher;
     private final InternalCallContextFactory internalCallContextFactory;
     private final AccountInternalApi accountApi;
-    private final InvoiceConfig invoiceConfig;
-    private final Clock clock;
 
     @Inject
-    public InvoiceListener(final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory,
-                           final InvoiceConfig invoiceConfig, final InvoiceDispatcher dispatcher) {
+    public InvoiceListener(final AccountInternalApi accountApi, final InternalCallContextFactory internalCallContextFactory, final InvoiceDispatcher dispatcher) {
         this.accountApi = accountApi;
         this.dispatcher = dispatcher;
-        this.invoiceConfig = invoiceConfig;
         this.internalCallContextFactory = internalCallContextFactory;
-        this.clock = clock;
     }
 
     @AllowConcurrentEvents
     @Subscribe
     public void handleRepairSubscriptionEvent(final RepairSubscriptionInternalEvent event) {
-
         try {
             final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "RepairBundle", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
-            dispatcher.processAccount(event.getAccountId(), event.getEffectiveDate(), null, context);
-        } catch (InvoiceApiException e) {
+            dispatcher.processAccount(event.getAccountId(), context.toLocalDate(event.getEffectiveDate()), null, context);
+        } catch (final InvoiceApiException e) {
             log.error(e.getMessage());
         }
     }
@@ -74,7 +68,6 @@ public class InvoiceListener {
     @AllowConcurrentEvents
     @Subscribe
     public void handleSubscriptionTransition(final EffectiveSubscriptionInternalEvent event) {
-
         try {
             //  Skip future uncancel event
             //  Skip events which are marked as not being the last one
@@ -85,15 +78,12 @@ public class InvoiceListener {
             }
             final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "SubscriptionBaseTransition", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
             dispatcher.processSubscriptionForInvoiceGeneration(event, context);
-        } catch (InvoiceApiException e) {
+        } catch (final InvoiceApiException e) {
             log.error(e.getMessage());
         }
     }
 
-    @AllowConcurrentEvents
-    @Subscribe
     public void handleBlockingStateTransition(final BlockingTransitionInternalEvent event) {
-
         // We are only interested in blockBilling or unblockBilling transitions.
         if (!event.isTransitionedToUnblockedBilling() && !event.isTransitionedToBlockedBilling()) {
             return;
@@ -102,10 +92,10 @@ public class InvoiceListener {
         try {
             final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "SubscriptionBaseTransition", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
             final UUID accountId = accountApi.getByRecordId(event.getSearchKey1(), context);
-            dispatcher.processAccount(accountId, clock.getUTCNow(), null, context);
-        } catch (InvoiceApiException e) {
+            dispatcher.processAccount(accountId, null, null, context);
+        } catch (final InvoiceApiException e) {
             log.error(e.getMessage());
-        } catch (AccountApiException e) {
+        } catch (final AccountApiException e) {
             log.error(e.getMessage());
         }
     }
@@ -113,8 +103,8 @@ public class InvoiceListener {
     public void handleNextBillingDateEvent(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
         try {
             final InternalCallContext context = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "Next Billing Date", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
-            dispatcher.processSubscriptionForInvoiceGeneration(subscriptionId, eventDateTime, context);
-        } catch (InvoiceApiException e) {
+            dispatcher.processSubscriptionForInvoiceGeneration(subscriptionId, context.toLocalDate(eventDateTime), context);
+        } catch (final InvoiceApiException e) {
             log.error(e.getMessage());
         }
     }
@@ -122,8 +112,8 @@ public class InvoiceListener {
     public void handleEventForInvoiceNotification(final UUID subscriptionId, final DateTime eventDateTime, final UUID userToken, final Long accountRecordId, final Long tenantRecordId) {
         try {
             final InternalCallContext context = internalCallContextFactory.createInternalCallContext(tenantRecordId, accountRecordId, "Next Billing Date", CallOrigin.INTERNAL, UserType.SYSTEM, userToken);
-            dispatcher.processSubscriptionForInvoiceNotification(subscriptionId, eventDateTime, context);
-        } catch (InvoiceApiException e) {
+            dispatcher.processSubscriptionForInvoiceNotification(subscriptionId, context.toLocalDate(eventDateTime), context);
+        } catch (final InvoiceApiException e) {
             log.error(e.getMessage());
         }
     }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java
index cb6ed8c..c8bc558 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/InvoiceTagHandler.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -18,18 +20,16 @@ package org.killbill.billing.invoice;
 
 import java.util.UUID;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.killbill.billing.ObjectType;
+import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.events.ControlTagDeletionInternalEvent;
 import org.killbill.billing.invoice.api.InvoiceApiException;
 import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.UserType;
-import org.killbill.clock.Clock;
-import org.killbill.billing.events.ControlTagDeletionInternalEvent;
 import org.killbill.billing.util.tag.ControlTagType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.AllowConcurrentEvents;
 import com.google.common.eventbus.Subscribe;
@@ -39,15 +39,12 @@ public class InvoiceTagHandler {
 
     private static final Logger log = LoggerFactory.getLogger(InvoiceTagHandler.class);
 
-    private final Clock clock;
     private final InvoiceDispatcher dispatcher;
     private final InternalCallContextFactory internalCallContextFactory;
 
     @Inject
-    public InvoiceTagHandler(final Clock clock,
-                             final InvoiceDispatcher dispatcher,
+    public InvoiceTagHandler(final InvoiceDispatcher dispatcher,
                              final InternalCallContextFactory internalCallContextFactory) {
-        this.clock = clock;
         this.dispatcher = dispatcher;
         this.internalCallContextFactory = internalCallContextFactory;
     }
@@ -55,7 +52,6 @@ public class InvoiceTagHandler {
     @AllowConcurrentEvents
     @Subscribe
     public void process_AUTO_INVOICING_OFF_removal(final ControlTagDeletionInternalEvent event) {
-
         if (event.getTagDefinition().getName().equals(ControlTagType.AUTO_INVOICING_OFF.toString()) && event.getObjectType() == ObjectType.ACCOUNT) {
             final UUID accountId = event.getObjectId();
             final InternalCallContext context = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "InvoiceTagHandler", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
@@ -65,8 +61,8 @@ public class InvoiceTagHandler {
 
     private void processUnpaid_AUTO_INVOICING_OFF_invoices(final UUID accountId, final InternalCallContext context) {
         try {
-            dispatcher.processAccount(accountId, clock.getUTCNow(), null, context);
-        } catch (InvoiceApiException e) {
+            dispatcher.processAccount(accountId, null, null, context);
+        } catch (final InvoiceApiException e) {
             log.warn(String.format("Failed to process process removal AUTO_INVOICING_OFF for account %s", accountId), e);
         }
     }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
index fd4b071..c455844 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/migration/TestDefaultInvoiceMigrationApi.java
@@ -23,7 +23,6 @@ import java.util.Collection;
 import java.util.List;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.catalog.api.Currency;
@@ -43,7 +42,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
     private final Logger log = LoggerFactory.getLogger(TestDefaultInvoiceMigrationApi.class);
 
     private LocalDate date_migrated;
-    private DateTime date_regular;
+    private LocalDate date_regular;
 
     private UUID accountId;
     private UUID migrationInvoiceId;
@@ -57,7 +56,7 @@ public class TestDefaultInvoiceMigrationApi extends InvoiceTestSuiteWithEmbedded
     public void beforeMethod() throws Exception {
         super.beforeMethod();
         date_migrated = clock.getUTCToday().minusYears(1);
-        date_regular = clock.getUTCNow();
+        date_regular = clock.getUTCToday();
 
         final Account account = invoiceUtil.createAccount(callContext);
         accountId = account.getId();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
index 2ff479d..57ebef6 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/api/user/TestDefaultInvoiceUserApi.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
  *
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
  * License.  You may obtain a copy of the License at:
  *
@@ -58,11 +60,9 @@ public class TestDefaultInvoiceUserApi extends InvoiceTestSuiteWithEmbeddedDB {
         super.beforeMethod();
         final Account account = invoiceUtil.createAccount(callContext);
         accountId = account.getId();
-        invoiceId = invoiceUtil.generateRegularInvoice(account, clock.getUTCNow(), callContext);
+        invoiceId = invoiceUtil.generateRegularInvoice(account, null, callContext);
     }
 
-
-
     @Test(groups = "slow")
     public void testPostExternalChargeOnNewInvoice() throws Exception {
         // Initial account balance
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
index 2bdde60..079900b 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceDispatcher.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
  *
  * The Billing Project licenses this file to you under the Apache License, version 2.0
  * (the "License"); you may not use this file except in compliance with the
@@ -84,7 +84,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
 
         Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<DryRunArguments>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
 
-        final DateTime target = effectiveDate;
+        final LocalDate target = internalCallContext.toLocalDate(effectiveDate);
 
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
@@ -144,7 +144,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
                                                                    internalCallContextFactory, invoiceNotifier, invoicePluginDispatcher, locker, busService.getBus(),
                                                                    null, invoiceConfig, clock);
 
-        final Invoice invoice = dispatcher.processAccount(account.getId(), new DateTime("2012-07-30T00:00:00.000Z"), null, context);
+        final Invoice invoice = dispatcher.processAccount(account.getId(), new LocalDate("2012-07-30"), null, context);
         Assert.assertNotNull(invoice);
 
         final List<InvoiceItem> invoiceItems = invoice.getInvoiceItems();
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
index 973d658..6b4020f 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -193,7 +193,7 @@ public class TestInvoiceHelper {
         this.invoiceConfig = invoiceConfig;
     }
 
-    public UUID generateRegularInvoice(final Account account, final DateTime targetDate, final CallContext callContext) throws Exception {
+    public UUID generateRegularInvoice(final Account account, final LocalDate targetDate, final CallContext callContext) throws Exception {
         final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
         Mockito.when(subscription.getId()).thenReturn(UUID.randomUUID());
         Mockito.when(subscription.getBundleId()).thenReturn(new UUID(0L, 0L));
@@ -258,12 +258,12 @@ public class TestInvoiceHelper {
 
         final Account account;
         if (isFastTest()) {
-            account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountUserApi, accountApi, immutableAccountApi, nonEntityDao, internalCallContextFactory, callContext, internalCallContext);
+            account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountUserApi, accountApi, immutableAccountApi, nonEntityDao, clock, internalCallContextFactory, callContext, internalCallContext);
         } else {
             account = accountUserApi.createAccount(accountData, callContext);
         }
 
-        GuicyKillbillTestSuite.refreshCallContext(account.getId(), internalCallContextFactory, callContext, internalCallContext);
+        GuicyKillbillTestSuite.refreshCallContext(account.getId(), clock, internalCallContextFactory, callContext, internalCallContext);
 
         return account;
     }
@@ -462,7 +462,7 @@ public class TestInvoiceHelper {
         }
 
         @Override
-        public DateTime getEffectiveDate() {
+        public LocalDate getEffectiveDate() {
             return null;
         }
 
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
index 9cda9fa..5e9e90f 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceNotificationQListener.java
@@ -33,7 +33,7 @@ public class TestInvoiceNotificationQListener extends InvoiceListener {
 
     @Inject
     public TestInvoiceNotificationQListener(final AccountInternalApi accountApi, final Clock clock, final InternalCallContextFactory internalCallContextFactory, final InvoiceDispatcher dispatcher) {
-        super(accountApi, clock, internalCallContextFactory, null, dispatcher);
+        super(accountApi, internalCallContextFactory, dispatcher);
     }
 
     @Override
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
index fed8945..85f268a 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/InvoiceResource.java
@@ -51,8 +51,6 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
@@ -105,7 +103,6 @@ import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.TenantContext;
 import org.killbill.billing.util.entity.Pagination;
 import org.killbill.clock.Clock;
-import org.killbill.clock.ClockUtil;
 import org.killbill.commons.metrics.TimedResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -366,7 +363,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);
 
-        final DryRunArguments dryRunArguments = new DefaultDryRunArguments(dryRunSubscriptionSpec, account.getTimeZone(), account.getCurrency(), clock);
+        final DryRunArguments dryRunArguments = new DefaultDryRunArguments(dryRunSubscriptionSpec, account);
         try {
             final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRunArguments,
                                                                                  callContext);
@@ -952,13 +949,13 @@ public class InvoiceResource extends JaxRsResourceBase {
         private final DryRunType dryRunType;
         private final SubscriptionEventType action;
         private final UUID subscriptionId;
-        private final DateTime effectiveDate;
+        private final LocalDate effectiveDate;
         private final PlanPhaseSpecifier specifier;
         private final UUID bundleId;
         private final BillingActionPolicy billingPolicy;
         private final List<PlanPhasePriceOverride> overrides;
 
-        public DefaultDryRunArguments(final InvoiceDryRunJson input, final DateTimeZone accountTimeZone, final Currency currency, final Clock clock) {
+        public DefaultDryRunArguments(final InvoiceDryRunJson input, final Account account) {
             if (input == null) {
                 this.dryRunType = DryRunType.TARGET_DATE;
                 this.action = null;
@@ -973,7 +970,7 @@ public class InvoiceResource extends JaxRsResourceBase {
                 this.action = input.getDryRunAction() != null ? SubscriptionEventType.valueOf(input.getDryRunAction()) : null;
                 this.subscriptionId = input.getSubscriptionId() != null ? UUID.fromString(input.getSubscriptionId()) : null;
                 this.bundleId = input.getBundleId() != null ? UUID.fromString(input.getBundleId()) : null;
-                this.effectiveDate = input.getEffectiveDate() != null ? ClockUtil.computeDateTimeWithUTCReferenceTime(input.getEffectiveDate(), clock.getUTCNow().toLocalTime(), accountTimeZone, clock) : null;
+                this.effectiveDate = input.getEffectiveDate();
                 this.billingPolicy = input.getBillingPolicy() != null ? BillingActionPolicy.valueOf(input.getBillingPolicy()) : null;
                 final PlanPhaseSpecifier planPhaseSpecifier = (input.getProductName() != null &&
                                                                input.getProductCategory() != null &&
@@ -991,9 +988,9 @@ public class InvoiceResource extends JaxRsResourceBase {
                                      @Override
                                      public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
                                          if (input.getPhaseName() != null) {
-                                             return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
+                                             return new DefaultPlanPhasePriceOverride(input.getPhaseName(), account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice());
                                          } else {
-                                             return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
+                                             return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, account.getCurrency(), input.getFixedPrice(), input.getRecurringPrice());
                                          }
                                      }
                                  })) : ImmutableList.<PlanPhasePriceOverride>of();
@@ -1021,7 +1018,7 @@ public class InvoiceResource extends JaxRsResourceBase {
         }
 
         @Override
-        public DateTime getEffectiveDate() {
+        public LocalDate getEffectiveDate() {
             return effectiveDate;
         }
 
@@ -1040,5 +1037,4 @@ public class InvoiceResource extends JaxRsResourceBase {
             return overrides;
         }
     }
-
 }
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index e286e85..57dd579 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -124,7 +124,7 @@ public class PaymentResource extends ComboPaymentResource {
     @TimedResource(name = "getPayment")
     @GET
     @Produces(APPLICATION_JSON)
-    @ApiOperation(value = "Retrieve a payment by id", response = PaymentJson.class)
+    @ApiOperation(value = "Retrieve a payment by external key", response = PaymentJson.class)
     @ApiResponses(value = {@ApiResponse(code = 404, message = "Payment not found")})
     public Response getPaymentByExternalKey(@QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                             @QueryParam(QUERY_EXTERNAL_KEY) final String paymentExternalKey,
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
index 84b3bc1..4cee36a 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BillCycleDayCalculator.java
@@ -42,6 +42,7 @@ import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
+import org.killbill.clock.ClockUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -143,7 +144,7 @@ public class BillCycleDayCalculator {
         }
 
         final DateTime date = plan.dateOfFirstRecurringNonZeroCharge(subscription.getStartDate(), initialPhaseType);
-        final int bcdLocal = context.toDateTime(date, account.getTimeZone()).getDayOfMonth();
+        final int bcdLocal = ClockUtil.toDateTime(date, account.getTimeZone()).getDayOfMonth();
         log.info("Calculated BCD: subscription id {}, subscription start {}, timezone {}, bcd {}",
                  subscription.getId(), date.toDateTimeISO(), account.getTimeZone(), bcdLocal);
 
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
index 106c179..1ef93cc 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/sm/TestPaymentLeavingStateCallback.java
@@ -121,8 +121,6 @@ public class TestPaymentLeavingStateCallback extends PaymentTestSuiteWithEmbedde
                                                            transactions.get(0).getId(), TransactionStatus.SUCCESS, BigDecimal.ONE, Currency.BRL,
                                                            "foo", "bar", internalCallContext);
 
-        internalCallContext.setAccountRecordId(123L);
-
         paymentStateContext = new PaymentStateContext(true,
                                                       paymentId,
                                                       null,
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
index ac1860e..5b56ec4 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
@@ -21,7 +21,7 @@ import java.math.BigDecimal;
 import java.util.List;
 import java.util.UUID;
 
-import org.joda.time.DateTimeZone;
+import org.killbill.billing.account.api.Account;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
@@ -37,13 +37,13 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
     @Test(groups = "slow")
     public void testPaymentCRUD() throws Exception {
         for (int i = 0; i < 3; i++) {
-            testPaymentCRUDForAccount(UUID.randomUUID(), i + 1);
+            testPaymentCRUDForAccount();
         }
     }
 
-    public void testPaymentCRUDForAccount(final UUID accountId, final int accountNb) {
-        // We need to create specific call contexts to make the account_record_id magic work
-        internalCallContext.setAccountRecordId((long) accountNb);
+    public void testPaymentCRUDForAccount() throws Exception {
+        final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+        final UUID accountId = account.getId();
 
         final PaymentModelDao specifiedFirstPaymentModelDao = generatePaymentModelDao(accountId);
         final PaymentTransactionModelDao specifiedFirstPaymentTransactionModelDao = generatePaymentTransactionModelDao(specifiedFirstPaymentModelDao.getId());
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
index d75b656..8bc6634 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
@@ -25,18 +25,16 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.killbill.billing.callcontext.InternalCallContext;
+import org.killbill.billing.account.api.Account;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.killbill.billing.payment.api.TransactionStatus;
 import org.killbill.billing.payment.api.TransactionType;
 import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
-import org.killbill.billing.util.callcontext.CallOrigin;
-import org.killbill.billing.util.callcontext.InternalCallContextFactory;
-import org.killbill.billing.util.callcontext.UserType;
 import org.killbill.billing.util.entity.Pagination;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -60,8 +58,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final TransactionType transactionType = TransactionType.AUTHORIZE;
         final String pluginName = "superPlugin";
 
-        final UUID accountId = UUID.randomUUID();
-
         final List<PluginProperty> properties = new ArrayList<PluginProperty>();
         properties.add(new PluginProperty("key1", "value1", false));
         properties.add(new PluginProperty("key2", "value2", false));
@@ -315,9 +311,8 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         // Just to guarantee that next clock.getUTCNow() > newTime
         try {
             Thread.sleep(1000);
-        } catch (InterruptedException e) {
+        } catch (final InterruptedException e) {
         }
-        ;
 
         final Iterable<PaymentTransactionModelDao> transactions2 = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.PENDING), clock.getUTCNow(), initialTime, 0L, 1L);
         for (PaymentTransactionModelDao paymentTransaction : transactions2) {
@@ -333,10 +328,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testPaymentByStatesAcrossTenants() {
-
-        final UUID paymentMethodId = UUID.randomUUID();
-        final UUID accountId = UUID.randomUUID();
+    public void testPaymentByStatesAcrossTenants() throws Exception {
         final String externalKey1 = "XXhhhhooo1";
         final String transactionExternalKey1 = "transactionXX1";
 
@@ -357,72 +349,72 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
 
         // Right before createdAfterDate, so should not be returned
         final DateTime createdDate1 = createdAfterDate.minusHours(1);
-        final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, accountId, paymentMethodId, externalKey1);
+        clock.setTime(createdDate1);
+        Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+        final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, account.getId(), account.getPaymentMethodId(), externalKey1);
         paymentModelDao1.setStateName("AUTH_ERRORED");
         final PaymentTransactionModelDao transaction1 = new PaymentTransactionModelDao(createdDate1, createdDate1, null, transactionExternalKey1,
                                                                                        paymentModelDao1.getId(), TransactionType.AUTHORIZE, createdDate1,
                                                                                        TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
                                                                                        "unknown", "");
 
-        internalCallContext.setAccountRecordId(1L);
-        internalCallContext.setCreatedDate(createdDate1);
-        internalCallContext.setUpdatedDate(createdDate1);
         paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, internalCallContext);
 
         // Right after createdAfterDate, so it should  be returned
         final DateTime createdDate2 = createdAfterDate.plusHours(1);
-        final PaymentModelDao paymentModelDao2 = new PaymentModelDao(createdDate2, createdDate2, accountId, paymentMethodId, externalKey2);
+        clock.setTime(createdDate2);
+        account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+        final PaymentModelDao paymentModelDao2 = new PaymentModelDao(createdDate2, createdDate2, account.getId(), account.getPaymentMethodId(), externalKey2);
         paymentModelDao2.setStateName("CAPTURE_ERRORED");
         final PaymentTransactionModelDao transaction2 = new PaymentTransactionModelDao(createdDate2, createdDate2, null, transactionExternalKey2,
                                                                                        paymentModelDao2.getId(), TransactionType.AUTHORIZE, createdDate2,
                                                                                        TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
                                                                                        "unknown", "");
 
-        internalCallContext.setAccountRecordId(2L);
-        internalCallContext.setCreatedDate(createdDate2);
-        internalCallContext.setUpdatedDate(createdDate2);
         paymentDao.insertPaymentWithFirstTransaction(paymentModelDao2, transaction2, internalCallContext);
 
         // Right before createdBeforeDate, so it should be returned
         final DateTime createdDate3 = createdBeforeDate.minusDays(1);
-        final PaymentModelDao paymentModelDao3 = new PaymentModelDao(createdDate3, createdDate3, accountId, paymentMethodId, externalKey3);
+        clock.setTime(createdDate3);
+        account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+        final PaymentModelDao paymentModelDao3 = new PaymentModelDao(createdDate3, createdDate3, account.getId(), account.getPaymentMethodId(), externalKey3);
         paymentModelDao3.setStateName("CAPTURE_ERRORED");
         final PaymentTransactionModelDao transaction3 = new PaymentTransactionModelDao(createdDate3, createdDate3, null, transactionExternalKey3,
                                                                                        paymentModelDao3.getId(), TransactionType.AUTHORIZE, createdDate3,
                                                                                        TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
                                                                                        "unknown", "");
 
-        internalCallContext.setAccountRecordId(3L);
-        internalCallContext.setCreatedDate(createdDate3);
-        internalCallContext.setUpdatedDate(createdDate3);
         paymentDao.insertPaymentWithFirstTransaction(paymentModelDao3, transaction3, internalCallContext);
 
         // Right before createdBeforeDate but with a SUCCESS state so it should NOT be returned
         final DateTime createdDate4 = createdBeforeDate.minusDays(1);
-        final PaymentModelDao paymentModelDao4 = new PaymentModelDao(createdDate4, createdDate4, accountId, paymentMethodId, externalKey4);
+        clock.setTime(createdDate4);
+        account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+        final PaymentModelDao paymentModelDao4 = new PaymentModelDao(createdDate4, createdDate4, account.getId(), account.getPaymentMethodId(), externalKey4);
         paymentModelDao4.setStateName("CAPTURE_SUCCESS");
         final PaymentTransactionModelDao transaction4 = new PaymentTransactionModelDao(createdDate4, createdDate4, null, transactionExternalKey4,
                                                                                        paymentModelDao4.getId(), TransactionType.AUTHORIZE, createdDate4,
                                                                                        TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
                                                                                        "unknown", "");
 
-        internalCallContext.setAccountRecordId(4L);
-        internalCallContext.setCreatedDate(createdDate4);
-        internalCallContext.setUpdatedDate(createdDate4);
         paymentDao.insertPaymentWithFirstTransaction(paymentModelDao4, transaction4, internalCallContext);
 
         // Right after createdBeforeDate, so it should NOT be returned
         final DateTime createdDate5 = createdBeforeDate.plusDays(1);
-        final PaymentModelDao paymentModelDao5 = new PaymentModelDao(createdDate5, createdDate5, accountId, paymentMethodId, externalKey5);
+        clock.setTime(createdDate5);
+        account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+        final PaymentModelDao paymentModelDao5 = new PaymentModelDao(createdDate5, createdDate5, account.getId(), account.getPaymentMethodId(), externalKey5);
         paymentModelDao5.setStateName("CAPTURE_ERRORED");
         final PaymentTransactionModelDao transaction5 = new PaymentTransactionModelDao(createdDate5, createdDate5, null, transactionExternalKey5,
                                                                                        paymentModelDao5.getId(), TransactionType.AUTHORIZE, createdDate5,
                                                                                        TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
                                                                                        "unknown", "");
 
-        internalCallContext.setAccountRecordId(5L);
-        internalCallContext.setCreatedDate(createdDate5);
-        internalCallContext.setUpdatedDate(createdDate5);
         paymentDao.insertPaymentWithFirstTransaction(paymentModelDao5, transaction5, internalCallContext);
 
         final String[] errorStates = {"AUTH_ERRORED", "CAPTURE_ERRORED", "REFUND_ERRORED", "CREDIT_ERRORED"};
@@ -431,25 +423,26 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testPaginationForPaymentByStatesAcrossTenants() {
-        // Right before createdAfterDate, so should not be returned
+    public void testPaginationForPaymentByStatesAcrossTenants() throws Exception {
         final DateTime createdDate1 = clock.getUTCNow().minusHours(1);
+        clock.setTime(createdDate1);
+
+        final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
 
         final int NB_ENTRIES = 30;
         for (int i = 0; i < NB_ENTRIES; i++) {
-            final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID().toString());
+            final PaymentModelDao paymentModelDao1 = new PaymentModelDao(createdDate1, createdDate1, account.getId(), account.getPaymentMethodId(), UUID.randomUUID().toString());
             final PaymentTransactionModelDao transaction1 = new PaymentTransactionModelDao(createdDate1, createdDate1, null, UUID.randomUUID().toString(),
                                                                                            paymentModelDao1.getId(), TransactionType.AUTHORIZE, createdDate1,
                                                                                            TransactionStatus.UNKNOWN, BigDecimal.TEN, Currency.AED,
                                                                                            "unknown", "");
 
-            internalCallContext.setAccountRecordId(1L);
-            internalCallContext.setCreatedDate(createdDate1);
-            internalCallContext.setUpdatedDate(createdDate1);
             paymentDao.insertPaymentWithFirstTransaction(paymentModelDao1, transaction1, internalCallContext);
         }
 
-        final Pagination<PaymentTransactionModelDao> result = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.UNKNOWN), clock.getUTCNow(), createdDate1, 0L, new Long(NB_ENTRIES));
+        clock.setTime(createdDate1.plusHours(1));
+
+        final Pagination<PaymentTransactionModelDao> result = paymentDao.getByTransactionStatusAcrossTenants(ImmutableList.of(TransactionStatus.UNKNOWN), clock.getUTCNow(), createdDate1, 0L, (long) NB_ENTRIES);
         Assert.assertEquals(result.getTotalNbRecords(), new Long(NB_ENTRIES));
 
         final Iterator<PaymentTransactionModelDao> iterator = result.iterator();
@@ -461,10 +454,7 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
     }
 
     @Test(groups = "slow")
-    public void testPaymentAttemptsByStateAcrossTenants() {
-
-        final UUID paymentMethodId = UUID.randomUUID();
-        final UUID accountId = UUID.randomUUID();
+    public void testPaymentAttemptsByStateAcrossTenants() throws Exception {
         final String externalKey1 = "gfhfg";
         final String transactionExternalKey1 = "sadas";
 
@@ -477,42 +467,41 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final String stateName = "FOO";
         final String pluginName = "miraculous";
 
-        final PaymentAttemptModelDao attempt1 = new PaymentAttemptModelDao(accountId, paymentMethodId, createdAfterDate, createdAfterDate, externalKey1,
+        clock.setTime(createdAfterDate);
+        Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+        final PaymentAttemptModelDao attempt1 = new PaymentAttemptModelDao(account.getId(), account.getPaymentMethodId(), createdAfterDate, createdAfterDate, externalKey1,
                                                                            UUID.randomUUID(), transactionExternalKey1, TransactionType.AUTHORIZE, stateName, BigDecimal.ONE, Currency.USD,
                                                                            ImmutableList.<String>of(pluginName), null);
 
-        final PaymentAttemptModelDao attempt2 = new PaymentAttemptModelDao(accountId, paymentMethodId, createdAfterDate, createdAfterDate, externalKey2,
+        paymentDao.insertPaymentAttemptWithProperties(attempt1, internalCallContext);
+
+        account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
+
+        final PaymentAttemptModelDao attempt2 = new PaymentAttemptModelDao(account.getId(), account.getPaymentMethodId(), createdAfterDate, createdAfterDate, externalKey2,
                                                                            UUID.randomUUID(), transactionExternalKey2, TransactionType.AUTHORIZE, stateName, BigDecimal.ONE, Currency.USD,
                                                                            ImmutableList.<String>of(pluginName), null);
 
-        internalCallContext.setAccountRecordId(1L);
-        internalCallContext.setCreatedDate(createdAfterDate);
-        internalCallContext.setUpdatedDate(createdAfterDate);
-        paymentDao.insertPaymentAttemptWithProperties(attempt1, internalCallContext);
-
-        internalCallContext.setAccountRecordId(2L);
-        internalCallContext.setCreatedDate(createdAfterDate);
-        internalCallContext.setUpdatedDate(createdAfterDate);
-        paymentDao.insertPaymentAttemptWithProperties(attempt2, internalCallContext);
+       paymentDao.insertPaymentAttemptWithProperties(attempt2, internalCallContext);
 
         final Pagination<PaymentAttemptModelDao> result = paymentDao.getPaymentAttemptsByStateAcrossTenants(stateName, createdBeforeDate, 0L, 2L);
         Assert.assertEquals(result.getTotalNbRecords().longValue(), 2L);
     }
 
     @Test(groups = "slow")
-    public void testUpdatePaymentAttempt() throws PluginPropertySerializerException {
+    public void testUpdatePaymentAttempt() throws Exception {
+        final DateTime createdAfterDate = clock.getUTCNow().minusDays(10);
+        clock.setTime(createdAfterDate);
+
+        final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
 
-        final UUID paymentMethodId = UUID.randomUUID();
-        final UUID accountId = UUID.randomUUID();
         final String externalKey1 = "2354";
         final String transactionExternalKey1 = "jkjkjk";
 
-        final DateTime createdAfterDate = clock.getUTCNow().minusDays(10);
-
         final String stateName = "RRRRR";
         final String pluginName = "elated";
 
-        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(accountId, paymentMethodId, createdAfterDate, createdAfterDate, externalKey1,
+        final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), account.getPaymentMethodId(), createdAfterDate, createdAfterDate, externalKey1,
                                                                           UUID.randomUUID(), transactionExternalKey1, TransactionType.AUTHORIZE, stateName, BigDecimal.ONE, Currency.USD,
                                                                           ImmutableList.<String>of(pluginName), null);
 
@@ -530,7 +519,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         properties.add(new PluginProperty("prop1", "value1", false));
         properties.add(new PluginProperty("prop2", "value2", false));
 
-
         final byte [] serializedProperties = PluginPropertySerializer.serialize(properties);
         paymentDao.updatePaymentAttemptWithProperties(rehydratedAttempt.getId(), transactionId, newStateName, serializedProperties, internalCallContext);
         final PaymentAttemptModelDao attempt2 = paymentDao.getPaymentAttempt(rehydratedAttempt.getId(), internalCallContext);
@@ -540,7 +528,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
         final Iterable<PluginProperty> properties2 = PluginPropertySerializer.deserialize(attempt2.getPluginProperties());
         checkProperty(properties2, new PluginProperty("prop1", "value1", false));
         checkProperty(properties2, new PluginProperty("prop2", "value2", false));
-
     }
 
     private void checkProperty(final Iterable<PluginProperty> properties, final PluginProperty expected) {
diff --git a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
index e52d7a3..0c47d84 100644
--- a/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
+++ b/payment/src/test/java/org/killbill/billing/payment/TestPaymentHelper.java
@@ -148,12 +148,12 @@ public class TestPaymentHelper {
 
         Account account;
         if (isFastTest()) {
-            account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountApi, accountInternalApi, immutableAccountInternalApi, nonEntityDao, internalCallContextFactory, context, internalCallContext);
+            account = GuicyKillbillTestSuiteNoDB.createMockAccount(accountData, accountApi, accountInternalApi, immutableAccountInternalApi, nonEntityDao, clock, internalCallContextFactory, context, internalCallContext);
         } else {
             account = accountApi.createAccount(accountData, context);
         }
 
-        GuicyKillbillTestSuite.refreshCallContext(account.getId(), internalCallContextFactory, context, internalCallContext);
+        GuicyKillbillTestSuite.refreshCallContext(account.getId(), clock, internalCallContextFactory, context, internalCallContext);
 
         if (addPaymentMethod) {
             final PaymentMethodPlugin pm = new DefaultNoOpPaymentMethodPlugin(UUID.randomUUID().toString(), true, null);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index a7354f3..9d0c003 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -512,7 +512,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                     case START_BILLING:
 
                         final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
-                        final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? dryRunArguments.getEffectiveDate() : utcNow;
+                        final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : utcNow;
                         final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, context);
                         final UUID subscriptionId = UUIDs.randomUUID();
                         dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, 1L, plan, inputSpec.getPhaseType(), realPriceList,
@@ -530,7 +530,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                     case CHANGE:
                         final DefaultSubscriptionBase subscriptionForChange = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), context);
-                        DateTime changeEffectiveDate = dryRunArguments.getEffectiveDate();
+                        DateTime changeEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : null;
                         if (changeEffectiveDate == null) {
                             BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
                             if (policy == null) {
@@ -547,7 +547,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                     case STOP_BILLING:
                         final DefaultSubscriptionBase subscriptionForCancellation = (DefaultSubscriptionBase) dao.getSubscriptionFromId(dryRunArguments.getSubscriptionId(), context);
-                        DateTime cancelEffectiveDate = dryRunArguments.getEffectiveDate();
+                        DateTime cancelEffectiveDate = dryRunArguments.getEffectiveDate() != null ? context.toUTCDateTime(dryRunArguments.getEffectiveDate()) : null;
                         if (dryRunArguments.getEffectiveDate() == null) {
                             BillingActionPolicy policy = dryRunArguments.getBillingActionPolicy();
                             if (policy == null) {
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
index 2e9b743..badf00a 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
@@ -30,6 +30,7 @@ import org.killbill.billing.platform.test.config.TestKillbillConfigSource;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.clock.Clock;
 import org.killbill.clock.ClockMock;
 import org.skife.config.ConfigSource;
 import org.slf4j.Logger;
@@ -103,6 +104,7 @@ public class GuicyKillbillTestSuite {
     }
 
     public static void refreshCallContext(final UUID accountId,
+                                          final Clock clock,
                                           final InternalCallContextFactory internalCallContextFactory,
                                           final TenantContext callContext,
                                           final MutableInternalCallContext internalCallContext) {
@@ -110,10 +112,12 @@ public class GuicyKillbillTestSuite {
         internalCallContext.setAccountRecordId(tmp.getAccountRecordId());
         internalCallContext.setFixedOffsetTimeZone(tmp.getFixedOffsetTimeZone());
         internalCallContext.setReferenceTime(tmp.getReferenceTime());
+        internalCallContext.setCreatedDate(clock.getUTCNow());
+        internalCallContext.setUpdatedDate(clock.getUTCNow());
     }
 
     protected void refreshCallContext(final UUID accountId) {
-        refreshCallContext(accountId, internalCallContextFactory, callContext, internalCallContext);
+        refreshCallContext(accountId, clock, internalCallContextFactory, callContext, internalCallContext);
     }
 
     @BeforeMethod(alwaysRun = true)
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java
index 0abf3c0..cc2e479 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuiteNoDB.java
@@ -29,6 +29,7 @@ import org.killbill.billing.dao.MockNonEntityDao;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.dao.NonEntityDao;
+import org.killbill.clock.Clock;
 import org.mockito.Mockito;
 
 public class GuicyKillbillTestSuiteNoDB extends GuicyKillbillTestSuite {
@@ -38,6 +39,7 @@ public class GuicyKillbillTestSuiteNoDB extends GuicyKillbillTestSuite {
                                             final AccountInternalApi accountInternalApi,
                                             final ImmutableAccountInternalApi immutableAccountInternalApi,
                                             final NonEntityDao nonEntityDao,
+                                            final Clock clock,
                                             final InternalCallContextFactory internalCallContextFactory,
                                             final CallContext callContext,
                                             final MutableInternalCallContext internalCallContext) throws AccountApiException {
@@ -51,7 +53,7 @@ public class GuicyKillbillTestSuiteNoDB extends GuicyKillbillTestSuite {
         ((MockNonEntityDao) nonEntityDao).addTenantRecordIdMapping(account.getId(), internalCallContext);
         ((MockNonEntityDao) nonEntityDao).addAccountRecordIdMapping(account.getId(), internalCallContext);
 
-        refreshCallContext(account.getId(), internalCallContextFactory, callContext, internalCallContext);
+        refreshCallContext(account.getId(), clock, internalCallContextFactory, callContext, internalCallContext);
 
         return account;
     }
diff --git a/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java b/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java
index 14d116d..49ecb00 100644
--- a/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java
+++ b/util/src/test/java/org/killbill/billing/util/callcontext/TestTimeAwareContext.java
@@ -23,11 +23,15 @@ import org.joda.time.LocalDate;
 import org.joda.time.format.DateTimeFormatter;
 import org.joda.time.format.ISODateTimeFormat;
 import org.killbill.billing.account.api.Account;
+import org.killbill.billing.callcontext.TimeAwareContext;
 import org.killbill.billing.mock.MockAccountBuilder;
 import org.killbill.billing.util.UtilTestSuiteNoDB;
 import org.killbill.billing.util.account.AccountDateTimeUtils;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableList;
+
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
@@ -139,6 +143,50 @@ public class TestTimeAwareContext extends UtilTestSuiteNoDB {
         assertEquals(internalCallContext.toLocalDate(dateTime3), new LocalDate("2015-11-30"));
     }
 
+    @Test(groups = "fast")
+    public void testIdempotencyOfDatesManipulation() throws Exception {
+        final ImmutableList.Builder<DateTimeZone> dateTimeZoneBuilder = ImmutableList.<DateTimeZone>builder();
+        dateTimeZoneBuilder.add(DateTimeZone.forID("HST"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("PST8PDT"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("MST"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("CST6CDT"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("EST"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("Brazil/DeNoronha"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("UTC"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("CET"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("Europe/Istanbul"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("Singapore"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("Japan"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("Australia/Sydney"));
+        dateTimeZoneBuilder.add(DateTimeZone.forID("Pacific/Tongatapu"));
+        final Iterable<DateTimeZone> dateTimeZones = dateTimeZoneBuilder.build();
+
+        final ImmutableList.Builder<DateTime> referenceDateTimeBuilder = ImmutableList.<DateTime>builder();
+        referenceDateTimeBuilder.add(new DateTime(2012, 1, 1, 1, 1, 1, DateTimeZone.UTC));
+        referenceDateTimeBuilder.add(new DateTime(2012, 3, 15, 12, 42, 0, DateTimeZone.forID("PST8PDT")));
+        referenceDateTimeBuilder.add(new DateTime(2012, 11, 15, 12, 42, 0, DateTimeZone.forID("PST8PDT")));
+        final Iterable<DateTime> referenceDateTimes = referenceDateTimeBuilder.build();
+
+        DateTime currentDateTime = new DateTime(2015, 1, 1, 1, 1, DateTimeZone.UTC);
+        final DateTime endDateTime = new DateTime(2020, 1, 1, 1, 1, DateTimeZone.UTC);
+        while (currentDateTime.compareTo(endDateTime) <= 0) {
+            for (final DateTimeZone dateTimeZone : dateTimeZones) {
+                for (final DateTime referenceDateTime : referenceDateTimes) {
+                    final TimeAwareContext timeAwareContext = new TimeAwareContext(dateTimeZone, referenceDateTime);
+
+                    final LocalDate computedLocalDate = timeAwareContext.toLocalDate(currentDateTime);
+                    final DateTime computedDateTime = timeAwareContext.toUTCDateTime(computedLocalDate);
+                    final LocalDate computedLocalDate2 = timeAwareContext.toLocalDate(computedDateTime);
+
+                    final String msg = String.format("currentDateTime=%s, localDate=%s, dateTime=%s, dateTimeZone=%s, referenceDateTime=%s", currentDateTime, computedLocalDate, computedDateTime, dateTimeZone, referenceDateTime);
+                    Assert.assertEquals(computedLocalDate2, computedLocalDate, msg);
+                }
+            }
+
+            currentDateTime = currentDateTime.plusHours(1);
+        }
+    }
+
     private void refreshCallContext(final DateTime effectiveDateTime, final DateTimeZone timeZone) {
         final Account account = new MockAccountBuilder().timeZone(timeZone)
                                                         .createdDate(effectiveDateTime)