killbill-aplcache

Changes

NEWS 3(+3 -0)

README.md 10(+10 -0)

Details

diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..01715d6
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,21 @@
+## How to contribute to Kill Bill
+
+**Do not open up a GitHub issue before reaching out to our [Mailing-List](https://groups.google.com/forum/#!forum/killbilling-users)**. GitHub issues are primarily intended for tracking bug reports and fixes by the core team.
+
+#### **Did you find a bug?**
+
+In your [Mailing-List](https://groups.google.com/forum/#!forum/killbilling-users) post, specify:
+
+* Step by step description on how to reproduce the issue
+* [Account data dump](https://github.com/killbill/killbill/wiki/Production-troubleshooting#exporting-account-data) of an affected account
+* [System information](https://github.com/killbill/killbill/wiki/Production-troubleshooting#exporting-system-information)
+
+#### **Do you intend to add a new feature or change an existing one?**
+
+Do not open an issue or pull request on GitHub until you have collected positive feedback about the change on the [Mailing-List](https://groups.google.com/forum/#!forum/killbilling-users).
+
+When submitting code, make sure to add [new tests](https://github.com/killbill/killbill/wiki/Navigating-the-Kill-Bill-codebase).
+
+#### **Do you want to contribute to the Kill Bill documentation?**
+
+Open a pull request on GitHub in the [killbill-docs](https://github.com/killbill/killbill-docs) repository.
diff --git a/api/src/main/java/org/killbill/billing/entitlement/EventsStream.java b/api/src/main/java/org/killbill/billing/entitlement/EventsStream.java
index be4eac4..f29f04e 100644
--- a/api/src/main/java/org/killbill/billing/entitlement/EventsStream.java
+++ b/api/src/main/java/org/killbill/billing/entitlement/EventsStream.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -20,9 +22,7 @@ import java.util.Collection;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
-
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.entitlement.api.BlockingState;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -32,8 +32,6 @@ public interface EventsStream {
 
     UUID getAccountId();
 
-    DateTimeZone getAccountTimeZone();
-
     UUID getBundleId();
 
     String getBundleExternalKey();
diff --git a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
index 4e32345..dfbe4f6 100644
--- a/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
+++ b/api/src/main/java/org/killbill/billing/junction/BillingEvent.java
@@ -1,7 +1,9 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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,22 +20,16 @@ package org.killbill.billing.junction;
 
 import java.math.BigDecimal;
 import java.util.List;
-import java.util.Set;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-
-import org.joda.time.LocalDate;
-import org.killbill.billing.account.api.Account;
-import org.killbill.billing.catalog.api.BillingMode;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
 import org.killbill.billing.catalog.api.Usage;
-import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 import org.killbill.billing.subscription.api.SubscriptionBase;
+import org.killbill.billing.subscription.api.SubscriptionBaseTransitionType;
 
 public interface BillingEvent extends Comparable<BillingEvent> {
 
@@ -101,11 +97,6 @@ public interface BillingEvent extends Comparable<BillingEvent> {
     Long getTotalOrdering();
 
     /**
-     * @return the TimeZone of the account
-     */
-    DateTimeZone getTimeZone();
-
-    /**
      *
      * @return the list of {@code Usage} section
      */
diff --git a/api/src/main/java/org/killbill/billing/overdue/applicator/formatters/BillingStateFormatter.java b/api/src/main/java/org/killbill/billing/overdue/applicator/formatters/BillingStateFormatter.java
index cfa2705..e33c7ba 100644
--- a/api/src/main/java/org/killbill/billing/overdue/applicator/formatters/BillingStateFormatter.java
+++ b/api/src/main/java/org/killbill/billing/overdue/applicator/formatters/BillingStateFormatter.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -22,7 +24,7 @@ public abstract class BillingStateFormatter extends BillingState {
 
     public BillingStateFormatter(final BillingState billingState) {
         super(billingState.getObjectId(), billingState.getNumberOfUnpaidInvoices(), billingState.getBalanceOfUnpaidInvoices(),
-              billingState.getDateOfEarliestUnpaidInvoice(), billingState.getAccountTimeZone(), billingState.getIdOfEarliestUnpaidInvoice(),
+              billingState.getDateOfEarliestUnpaidInvoice(), billingState.getIdOfEarliestUnpaidInvoice(),
               billingState.getResponseForLastFailedPayment(), billingState.getTags());
     }
 
diff --git a/api/src/main/java/org/killbill/billing/overdue/config/api/BillingState.java b/api/src/main/java/org/killbill/billing/overdue/config/api/BillingState.java
index dfdc986..fa78e0f 100644
--- a/api/src/main/java/org/killbill/billing/overdue/config/api/BillingState.java
+++ b/api/src/main/java/org/killbill/billing/overdue/config/api/BillingState.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -22,9 +22,7 @@ import java.math.BigDecimal;
 import java.util.Arrays;
 import java.util.UUID;
 
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
-
 import org.killbill.billing.payment.api.PaymentResponse;
 import org.killbill.billing.util.tag.Tag;
 
@@ -34,7 +32,6 @@ public class BillingState {
     private final int numberOfUnpaidInvoices;
     private final BigDecimal balanceOfUnpaidInvoices;
     private final LocalDate dateOfEarliestUnpaidInvoice;
-    private final DateTimeZone accountTimeZone;
     private final UUID idOfEarliestUnpaidInvoice;
     private final PaymentResponse responseForLastFailedPayment;
     private final Tag[] tags;
@@ -43,7 +40,6 @@ public class BillingState {
                         final int numberOfUnpaidInvoices,
                         final BigDecimal balanceOfUnpaidInvoices,
                         final LocalDate dateOfEarliestUnpaidInvoice,
-                        final DateTimeZone accountTimeZone,
                         final UUID idOfEarliestUnpaidInvoice,
                         final PaymentResponse responseForLastFailedPayment,
                         final Tag[] tags) {
@@ -51,7 +47,6 @@ public class BillingState {
         this.numberOfUnpaidInvoices = numberOfUnpaidInvoices;
         this.balanceOfUnpaidInvoices = balanceOfUnpaidInvoices;
         this.dateOfEarliestUnpaidInvoice = dateOfEarliestUnpaidInvoice;
-        this.accountTimeZone = accountTimeZone;
         this.idOfEarliestUnpaidInvoice = idOfEarliestUnpaidInvoice;
         this.responseForLastFailedPayment = responseForLastFailedPayment;
         this.tags = tags;
@@ -85,10 +80,6 @@ public class BillingState {
         return tags;
     }
 
-    public DateTimeZone getAccountTimeZone() {
-        return accountTimeZone;
-    }
-
     @Override
     public String toString() {
         final StringBuilder sb = new StringBuilder("BillingState{");
@@ -96,7 +87,6 @@ public class BillingState {
         sb.append(", numberOfUnpaidInvoices=").append(numberOfUnpaidInvoices);
         sb.append(", balanceOfUnpaidInvoices=").append(balanceOfUnpaidInvoices);
         sb.append(", dateOfEarliestUnpaidInvoice=").append(dateOfEarliestUnpaidInvoice);
-        sb.append(", accountTimeZone=").append(accountTimeZone);
         sb.append(", idOfEarliestUnpaidInvoice=").append(idOfEarliestUnpaidInvoice);
         sb.append(", responseForLastFailedPayment=").append(responseForLastFailedPayment);
         sb.append(", tags=").append(Arrays.toString(tags));
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java
index 5d2e050..b581b4c 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBase.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -20,8 +22,6 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-
-import org.joda.time.DateTimeZone;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Plan;
@@ -47,7 +47,7 @@ public interface SubscriptionBase extends Entity, Blockable {
     public boolean cancelWithDate(final DateTime requestedDate, final CallContext context)
             throws SubscriptionBaseApiException;
 
-    public boolean cancelWithPolicy(final BillingActionPolicy policy, final DateTimeZone accountTimeZone, int accountBillCycleDayLocal, final CallContext context)
+    public boolean cancelWithPolicy(final BillingActionPolicy policy, int accountBillCycleDayLocal, final CallContext context)
             throws SubscriptionBaseApiException;
 
     public boolean uncancel(final CallContext context)
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
index 9530310..3bc9cb9 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseInternalApi.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2011 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -25,7 +25,6 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.callcontext.InternalTenantContext;
@@ -50,7 +49,7 @@ public interface SubscriptionBaseInternalApi {
     public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(UUID accountId, Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifier,
                                                                               InternalCallContext contextWithValidAccountRecordId) throws SubscriptionBaseApiException;
 
-    public void cancelBaseSubscriptions(Iterable<SubscriptionBase> subscriptions, BillingActionPolicy policy, DateTimeZone accountTimeZone, int accountBillCycleDayLocal, InternalCallContext context) throws SubscriptionBaseApiException;
+    public void cancelBaseSubscriptions(Iterable<SubscriptionBase> subscriptions, BillingActionPolicy policy, int accountBillCycleDayLocal, InternalCallContext context) throws SubscriptionBaseApiException;
 
     public SubscriptionBaseBundle createBundleForAccount(UUID accountId, String bundleName, InternalCallContext context)
             throws SubscriptionBaseApiException;
@@ -101,5 +100,5 @@ public interface SubscriptionBaseInternalApi {
 
     public void updateBCD(final UUID subscriptionId, final int bcd, @Nullable final LocalDate effectiveFromDate, final InternalCallContext internalCallContext) throws SubscriptionBaseApiException;
 
-    public int getDefaultBillCycleDayLocal(final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final PlanPhaseSpecifier planPhaseSpecifier, final DateTimeZone accountTimeZone, final int accountBillCycleDayLocal, final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException;
+    public int getDefaultBillCycleDayLocal(final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final PlanPhaseSpecifier planPhaseSpecifier, final int accountBillCycleDayLocal, final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException;
 }
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 de723e3..2c1cc04 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
@@ -48,6 +48,8 @@ import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
 
+import static org.testng.Assert.assertEquals;
+
 public class TestWithTimeZones extends TestIntegrationBase {
 
     // Verify that recurring invoice items are correctly computed although we went through and out of daylight saving transitions
@@ -254,4 +256,155 @@ public class TestWithTimeZones extends TestIntegrationBase {
             invoiceChecker.checkChargedThroughDate(entitlement.getId(), new LocalDate("2015-03-08").plusMonths(3 + i), callContext);
         }
     }
+
+
+    @Test(groups = "slow")
+    public void testIntoDaylightSavingTransition() throws Exception {
+
+        // Daylight saving happened on March 12th.
+        //
+        // Because we use 30 days trial, we start a bit before and that way we can check that computation of BCD crossing into daylight saving works as expected.
+        //
+        final DateTimeZone tz = DateTimeZone.forID("America/Los_Angeles");
+        clock.setTime(new DateTime(2017, 3, 1, 23, 30, 0, tz));
+
+        final AccountData accountData = new MockAccountBuilder().currency(Currency.USD)
+                                                                .timeZone(tz)
+                                                                .build();
+
+        // Create account with non BCD to force junction BCD logic to activate
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+
+        createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY,  NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+
+        final Account accountWithBCD = accountUserApi.getAccountById(account.getId(), callContext);
+        assertEquals(accountWithBCD.getBillCycleDayLocal().intValue(), 31);
+
+        busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        clock.addDays(30);
+        assertListenerStatus();
+
+
+        final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2017, 3, 31), new LocalDate(2017, 4, 30), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+        invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
+        expectedInvoices.clear();
+    }
+
+
+
+
+    @Test(groups = "slow")
+    public void testIntoDaylightSavingTransition2() throws Exception {
+
+        //
+        // Nov 6th Transition date from DST -> ST
+        //
+        // Because we use 30 days trial, we start a bit before and that way we can check that computation of BCD crossing into daylight saving works as expected.
+        //
+        final DateTimeZone tz = DateTimeZone.forID("America/Los_Angeles");
+        clock.setTime(new DateTime(2016, 11, 5, 23, 30, 0, tz));
+
+        final AccountData accountData = new MockAccountBuilder().currency(Currency.USD)
+                                                                .timeZone(tz)
+                                                                .build();
+
+        // Create account with non BCD to force junction BCD logic to activate
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+
+        clock.setTime(new DateTime(2017, 3, 1, 23, 30, 0, tz));
+
+        createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY,  NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+
+        final Account accountWithBCD = accountUserApi.getAccountById(account.getId(), callContext);
+        //
+        // Ok, it's a little bit tricky here:
+        //
+        // Intuitively we would expect a BCD of 31 (same as previous test testIntoDaylightSavingTransition1), however our implementation relies on TimeAwareContext for all TZ
+        // computation. This context stores an offset from UTC which is then used as a reference and because we created an account before Nov 6 (DST), the offest is (-7)
+        // so the result is different than previous test (where offset was -8)
+        // What 's important is the fact that BCD and invoiceDate align in such a way that:
+        // 1. we see no leading pro-ration
+        // 2. Invoice is correctly generated (don't miss it because too early or don't invoice loop)
+        //
+        assertEquals(accountWithBCD.getBillCycleDayLocal().intValue(), 1);
+
+        busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        clock.addDays(30);
+        assertListenerStatus();
+
+
+        final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2017, 4, 1), new LocalDate(2017, 5, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+        invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
+        expectedInvoices.clear();
+    }
+
+
+    @Test(groups = "slow")
+    public void testIntoDaylightSavingTransition3() throws Exception {
+
+        final DateTimeZone tz = DateTimeZone.forID("America/Los_Angeles");
+        clock.setTime(new DateTime(2017, 3, 1, 23, 30, 0, tz));
+
+
+        final AccountData accountData = new MockAccountBuilder().currency(Currency.USD)
+                                                                .timeZone(tz)
+                                                                .build();
+
+        // Create account with non BCD to force junction BCD logic to activate
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("pistol-monthly-notrial",null);
+        busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE, NextEvent.INVOICE_PAYMENT, NextEvent.PAYMENT);
+        entitlementApi.createBaseEntitlement(account.getId(), spec, "bundleExternalKey", ImmutableList.<PlanPhasePriceOverride>of(), null, null, false, ImmutableList.<PluginProperty>of(), callContext);
+        assertListenerStatus();
+
+
+        busHandler.pushExpectedEvents(NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        // Technically, we should see the invoice at the end of day in the account timezone, but this is not the case, the invoice comes slightly after (30')
+        // clock.setTime(new DateTime(2017, 4, 1, 23, 59, 0, tz));
+        //
+        // But this is really not very important as long as invoicing is correct
+        clock.addMonths(1);
+        // Add one hour to hit the notification date of 2017-04-02T07:30:00.000Z
+        clock.addDeltaFromReality(3600 * 1000);
+        assertListenerStatus();
+    }
+
+
+
+    @Test(groups = "slow")
+    public void testOutOfDaylightSavingTransition1() throws Exception {
+
+        // Transition out of daylight saving is set for Nov 5
+        //
+        // Because we use 30 days trial, we start a bit before and that way we can check that computation of BCD crossing out of of daylight saving works as expected.
+        //
+        final DateTimeZone tz = DateTimeZone.forID("America/Los_Angeles");
+        clock.setTime(new DateTime(2017, 11, 1, 00, 30, 0, tz));
+
+        final AccountData accountData = new MockAccountBuilder().currency(Currency.USD)
+                                                                .timeZone(tz)
+                                                                .build();
+
+        // Create account with non BCD to force junction BCD logic to activate
+        final Account account = createAccountWithNonOsgiPaymentMethod(accountData);
+
+        createBaseEntitlementAndCheckForCompletion(account.getId(), "bundleKey", "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY,  NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
+
+        final Account accountWithBCD = accountUserApi.getAccountById(account.getId(), callContext);
+        assertEquals(accountWithBCD.getBillCycleDayLocal().intValue(), 1);
+
+        busHandler.pushExpectedEvents(NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
+        clock.addDays(30);
+        assertListenerStatus();
+
+
+        final List<ExpectedInvoiceItemCheck> expectedInvoices = new ArrayList<ExpectedInvoiceItemCheck>();
+        expectedInvoices.add(new ExpectedInvoiceItemCheck(new LocalDate(2017, 12, 1), new LocalDate(2018, 1, 1), InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+        invoiceChecker.checkInvoice(account.getId(), 2, callContext, expectedInvoices);
+        expectedInvoices.clear();
+    }
+
 }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
index ba099eb..ad4fcc5 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -18,9 +18,16 @@
 
 package org.killbill.billing.entitlement.api;
 
-import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalCallContext;
@@ -67,13 +74,7 @@ import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificatio
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.Nullable;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.UUID;
+import com.google.common.collect.ImmutableList;
 
 import static org.killbill.billing.entitlement.logging.EntitlementLoggingHelper.logCancelEntitlement;
 import static org.killbill.billing.entitlement.logging.EntitlementLoggingHelper.logChangePlan;
@@ -155,10 +156,6 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         return eventsStream;
     }
 
-    public DateTimeZone getAccountTimeZone() {
-        return eventsStream.getAccountTimeZone();
-    }
-
     // Subscription associated with this entitlement (equals to baseSubscription for base subscriptions)
     public SubscriptionBase getSubscriptionBase() {
         return eventsStream.getSubscriptionBase();
@@ -300,7 +297,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         // Get the latest state from disk - required to have the latest CTD
         refresh(callContext);
 
-        final LocalDate cancellationDate = getLocalDateFromEntitlementPolicy(entitlementPolicy);
+        final LocalDate cancellationDate = getLocalDateFromEntitlementPolicy(entitlementPolicy, callContext);
         return cancelEntitlementWithDate(cancellationDate, false, properties, callContext);
     }
 
@@ -453,7 +450,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         // Get the latest state from disk - required to have the latest CTD
         refresh(callContext);
 
-        final LocalDate cancellationDate = getLocalDateFromEntitlementPolicy(entitlementPolicy);
+        final LocalDate cancellationDate = getLocalDateFromEntitlementPolicy(entitlementPolicy, callContext);
         return cancelEntitlementWithDateOverrideBillingPolicy(cancellationDate, billingPolicy, properties, callContext);
     }
 
@@ -496,7 +493,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
                 try {
                     // Cancel subscription base first, to correctly compute the add-ons entitlements we need to cancel (see below)
-                    getSubscriptionBase().cancelWithPolicy(billingPolicy, eventsStream.getAccountTimeZone(), eventsStream.getDefaultBillCycleDayLocal(), callContext);
+                    getSubscriptionBase().cancelWithPolicy(billingPolicy, eventsStream.getDefaultBillCycleDayLocal(), callContext);
                 } catch (final SubscriptionBaseApiException e) {
                     throw new EntitlementApiException(e);
                 }
@@ -518,18 +515,19 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         return pluginExecution.executeWithPlugin(cancelEntitlementWithPlugin, pluginContext);
     }
 
-    private LocalDate getLocalDateFromEntitlementPolicy(final EntitlementActionPolicy entitlementPolicy) {
+    private LocalDate getLocalDateFromEntitlementPolicy(final EntitlementActionPolicy entitlementPolicy, final TenantContext tenantContext) {
+        final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(getAccountId(), tenantContext);
 
         final LocalDate cancellationDate;
         switch (entitlementPolicy) {
             case IMMEDIATE:
-                cancellationDate = clock.getToday(eventsStream.getAccountTimeZone());
+                cancellationDate = internalTenantContext.toLocalDate(clock.getUTCNow());
                 break;
             case END_OF_TERM:
                 if (getSubscriptionBase().getChargedThroughDate() != null) {
                     cancellationDate = internalTenantContext.toLocalDate(getSubscriptionBase().getChargedThroughDate());
                 } else {
-                    cancellationDate = clock.getToday(eventsStream.getAccountTimeZone());
+                    cancellationDate = internalTenantContext.toLocalDate(clock.getUTCNow());
                 }
                 break;
             default:
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index 1ea62df..9035ffe 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -280,7 +280,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
         }
 
 
-        final LocalDate effectiveDate = new LocalDate(clock.getUTCNow(), account.getTimeZone());
+        final LocalDate effectiveDate = internalCallContext.toLocalDate(clock.getUTCNow());
         final BaseEntitlementWithAddOnsSpecifier baseEntitlementWithAddOnsSpecifier = new DefaultBaseEntitlementWithAddOnsSpecifier(
                 bundleId,
                 newExternalKey,
@@ -425,11 +425,11 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
                                                                        }
                                                                    }) : filteredByTypes;
 
-            final LocalDate localDateNowInAccountTimezone = new LocalDate(clock.getUTCNow(), account.getTimeZone());
+            final LocalDate localDateNowInAccountTimezone = internalTenantContextWithValidAccountRecordId.toLocalDate(clock.getUTCNow());
             final List<BlockingState> result = new ArrayList<BlockingState>();
             for (final BlockingState cur : filteredByTypesAndSvcs) {
 
-                final LocalDate eventDate = new LocalDate(cur.getEffectiveDate(), account.getTimeZone());
+                final LocalDate eventDate = internalTenantContextWithValidAccountRecordId.toLocalDate(cur.getEffectiveDate());
                 final int comp = eventDate.compareTo(localDateNowInAccountTimezone);
                 if ((comp <= 1 && ((timeFilter & SubscriptionApi.PAST_EVENTS) == SubscriptionApi.PAST_EVENTS)) ||
                     (comp == 0 && ((timeFilter & SubscriptionApi.PRESENT_EVENTS) == SubscriptionApi.PRESENT_EVENTS)) ||
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
index 21845a5..2f52230 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/EntitlementDateHelper.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -21,7 +21,6 @@ package org.killbill.billing.entitlement.api;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.clock.Clock;
@@ -38,24 +37,8 @@ public class EntitlementDateHelper {
         return requestedDate == null ? clock.getUTCNow() : callContext.toUTCDateTime(requestedDate);
     }
 
-
     public DateTime fromLocalDateAndReferenceTimeWithMinimum(@Nullable final LocalDate requestedDate, final DateTime min, final InternalTenantContext callContext) throws EntitlementApiException {
         final DateTime candidate = fromLocalDateAndReferenceTime(requestedDate, callContext);
         return candidate.compareTo(min) < 0 ? min : candidate;
     }
-
-    /**
-     * Check if the date portion of a date/time is before or equals at now (as returned by the clock).
-     *
-     * @param inputDate             the fully qualified DateTime
-     * @param accountTimeZone       the account timezone
-     * @param internalTenantContext the context
-     * @return true if the inputDate, once converted into a LocalDate using account timezone is less or equals than today
-     */
-    // TODO Move to ClockUtils
-    public boolean isBeforeOrEqualsToday(final DateTime inputDate, final DateTimeZone accountTimeZone, final InternalTenantContext internalTenantContext) {
-        final LocalDate localDateNowInAccountTimezone = clock.getToday(accountTimeZone);
-        final LocalDate targetDateInAccountTimezone = internalTenantContext.toLocalDate(inputDate);
-        return targetDateInAccountTimezone.compareTo(localDateNowInAccountTimezone) <= 0;
-    }
 }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
index 5a59a28..de22aaf 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -32,12 +32,10 @@ import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalCallContext;
-import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.entitlement.DefaultEntitlementService;
 import org.killbill.billing.entitlement.EntitlementInternalApi;
@@ -103,15 +101,13 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
             return;
         }
 
-        int bcd = 0;
-        DateTimeZone accountTimeZone = null;
+        int bcd;
         try {
             bcd = accountApi.getBCD(entitlements.iterator().next().getAccountId(), internalCallContext);
-            accountTimeZone = accountApi.getImmutableAccountDataByRecordId(internalCallContext. getAccountRecordId(), internalCallContext).getTimeZone();
         } catch (final AccountApiException e) {
             throw new EntitlementApiException(e);
         }
-        Preconditions.checkState(bcd > 0 && accountTimeZone != null, "Unexpected condition where account info could not be retrieved");
+        Preconditions.checkState(bcd > 0, "Unexpected condition where account info could not be retrieved");
 
         final CallContext callContext = internalCallContextFactory.createCallContext(internalCallContext);
 
@@ -158,7 +154,6 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
 
         final Callable<Void> preCallbacksCallback = new BulkSubscriptionBaseCancellation(subscriptions,
                                                                                          billingPolicy,
-                                                                                         accountTimeZone,
                                                                                          bcd,
                                                                                          internalCallContext);
 
@@ -191,18 +186,15 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
 
         private final Iterable<SubscriptionBase> subscriptions;
         private final BillingActionPolicy billingPolicy;
-        private final DateTimeZone accountTimeZone;
         private final int accountBillCycleDayLocal;
         private final InternalCallContext callContext;
 
         public BulkSubscriptionBaseCancellation(final Iterable<SubscriptionBase> subscriptions,
                                                 final BillingActionPolicy billingPolicy,
-                                                final DateTimeZone accountTimeZone,
                                                 final int accountBillCycleDayLocal,
                                                 final InternalCallContext callContext) {
             this.subscriptions = subscriptions;
             this.billingPolicy = billingPolicy;
-            this.accountTimeZone = accountTimeZone;
             this.accountBillCycleDayLocal = accountBillCycleDayLocal;
             this.callContext = callContext;
         }
@@ -210,7 +202,7 @@ public class DefaultEntitlementInternalApi extends DefaultEntitlementApiBase imp
         @Override
         public Void call() throws Exception {
             try {
-                subscriptionInternalApi.cancelBaseSubscriptions(subscriptions, billingPolicy, accountTimeZone, accountBillCycleDayLocal, callContext);
+                subscriptionInternalApi.cancelBaseSubscriptions(subscriptions, billingPolicy, accountBillCycleDayLocal, callContext);
             } catch (final SubscriptionBaseApiException e) {
                 throw new EntitlementApiException(e);
             }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
index eded306..27d9591 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/DefaultEventsStream.java
@@ -27,7 +27,6 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.callcontext.InternalTenantContext;
@@ -70,6 +69,7 @@ public class DefaultEventsStream implements EventsStream {
     private final List<SubscriptionBase> allSubscriptionsForBundle;
     private final InternalTenantContext internalTenantContext;
     private final DateTime utcNow;
+    private final LocalDate utcToday;
     private final int defaultBillCycleDayLocal;
 
     private BlockingAggregator blockingAggregator;
@@ -100,16 +100,12 @@ public class DefaultEventsStream implements EventsStream {
         this.defaultBillCycleDayLocal = defaultBillCycleDayLocal;
         this.internalTenantContext = contextWithValidAccountRecordId;
         this.utcNow = utcNow;
+        this.utcToday = contextWithValidAccountRecordId.toLocalDate(utcNow);
 
         setup();
     }
 
     @Override
-    public DateTimeZone getAccountTimeZone() {
-        return account.getTimeZone();
-    }
-
-    @Override
     public UUID getAccountId() {
         return account.getId();
     }
@@ -462,7 +458,7 @@ public class DefaultEventsStream implements EventsStream {
         if (entitlementEffectiveEndDate != null && entitlementEffectiveEndDate.compareTo(internalTenantContext.toLocalDate(utcNow)) <= 0) {
             entitlementState = EntitlementState.CANCELLED;
         } else {
-            if (entitlementEffectiveStartDate.compareTo(new LocalDate(utcNow, account.getTimeZone())) > 0) {
+            if (entitlementEffectiveStartDate.compareTo(utcToday) > 0) {
                 entitlementState = EntitlementState.PENDING;
             } else {
                 // Gather states across all services and check if one of them is set to 'blockEntitlement'
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
index 35ce153..b2b436a 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/engine/core/EventsStreamBuilder.java
@@ -338,7 +338,7 @@ public class EventsStreamBuilder {
 
         try {
             int accountBCD = accountInternalApi.getBCD(account.getId(), internalTenantContext);
-            int defaultAlignmentDay = subscriptionInternalApi.getDefaultBillCycleDayLocal(bcdCache, subscription, baseSubscription, createPlanPhaseSpecifier(subscription), account.getTimeZone(), accountBCD, clock.getUTCNow(), internalTenantContext);
+            int defaultAlignmentDay = subscriptionInternalApi.getDefaultBillCycleDayLocal(bcdCache, subscription, baseSubscription, createPlanPhaseSpecifier(subscription), accountBCD, clock.getUTCNow(), internalTenantContext);
             return new DefaultEventsStream(account,
                                            bundle,
                                            blockingStates,
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 07ddabf..3c4b79f 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
@@ -26,6 +26,7 @@ import org.joda.time.LocalDate;
 import org.killbill.billing.GuicyKillbillTestSuiteNoDB;
 import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.entitlement.EntitlementTestSuiteNoDB;
 import org.killbill.billing.mock.MockAccountBuilder;
 import org.testng.Assert;
@@ -124,7 +125,21 @@ public class TestEntitlementDateHelper extends EntitlementTestSuiteNoDB {
         // Check that our input date is greater than now
         assertTrue(inputDateEquals.compareTo(clock.getUTCNow()) > 0);
         // And yet since the LocalDate match the function returns true
-        assertTrue(dateHelper.isBeforeOrEqualsToday(inputDateEquals, timeZoneUtcMinus8, internalCallContext));
+        assertTrue(isBeforeOrEqualsToday(inputDateEquals, timeZoneUtcMinus8, internalCallContext));
+    }
+
+    /**
+     * Check if the date portion of a date/time is before or equals at now (as returned by the clock).
+     *
+     * @param inputDate             the fully qualified DateTime
+     * @param accountTimeZone       the account timezone
+     * @param internalTenantContext the context
+     * @return true if the inputDate, once converted into a LocalDate using account timezone is less or equals than today
+     */
+    private boolean isBeforeOrEqualsToday(final DateTime inputDate, final DateTimeZone accountTimeZone, final InternalTenantContext internalTenantContext) {
+        final LocalDate localDateNowInAccountTimezone = clock.getToday(accountTimeZone);
+        final LocalDate targetDateInAccountTimezone = internalTenantContext.toLocalDate(inputDate);
+        return targetDateInAccountTimezone.compareTo(localDateNowInAccountTimezone) <= 0;
     }
 
     private void createAccount(final DateTimeZone dateTimeZone, final DateTime referenceDateTime) throws AccountApiException {
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 06ee314..dc90d85 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/TestInvoiceHelper.java
@@ -408,11 +408,6 @@ public class TestInvoiceHelper {
             }
 
             @Override
-            public DateTimeZone getTimeZone() {
-                return DateTimeZone.UTC;
-            }
-
-            @Override
             public List<Usage> getUsages() {
                 return Collections.emptyList();
             }
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
index e8ba727..0c1f557 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/usage/TestUsageInArrearBase.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -138,7 +138,6 @@ public abstract class TestUsageInArrearBase extends InvoiceTestSuiteNoDB {
         final BillingEvent result = Mockito.mock(BillingEvent.class);
         Mockito.when(result.getCurrency()).thenReturn(Currency.BTC);
         Mockito.when(result.getBillCycleDayLocal()).thenReturn(BCD);
-        Mockito.when(result.getTimeZone()).thenReturn(DateTimeZone.UTC);
         Mockito.when(result.getEffectiveDate()).thenReturn(effectiveDate);
         Mockito.when(result.getBillingPeriod()).thenReturn(billingPeriod);
 
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
index 76ec20d..3ff89c4 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -33,7 +33,6 @@ import java.util.concurrent.atomic.AtomicLong;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.Days;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingPeriod;
@@ -277,12 +276,11 @@ public class BlockingCalculator {
         final String description = "";
         final SubscriptionBaseTransitionType type = SubscriptionBaseTransitionType.START_BILLING_DISABLED;
         final Long totalOrdering = globaltotalOrder.getAndIncrement();
-        final DateTimeZone tz = previousEvent.getTimeZone();
 
         return new DefaultBillingEvent(subscription, effectiveDate, true, plan, planPhase, fixedPrice,
                                        currency,
                                        billingPeriod, billCycleDay,
-                                       description, totalOrdering, type, tz, catalog, true);
+                                       description, totalOrdering, type, catalog, true);
     }
 
     protected BillingEvent createNewReenableEvent(final DateTime odEventTime, final BillingEvent previousEvent, final Catalog catalog, final InternalTenantContext context) throws CatalogApiException {
@@ -298,12 +296,11 @@ public class BlockingCalculator {
         final BillingPeriod billingPeriod = previousEvent.getBillingPeriod();
         final SubscriptionBaseTransitionType type = SubscriptionBaseTransitionType.END_BILLING_DISABLED;
         final Long totalOrdering = globaltotalOrder.getAndIncrement();
-        final DateTimeZone tz = previousEvent.getTimeZone();
 
         return new DefaultBillingEvent(subscription, effectiveDate, true, plan, planPhase, fixedPrice,
                                        currency,
                                        billingPeriod, billCycleDay,
-                                       description, totalOrdering, type, tz, catalog, false);
+                                       description, totalOrdering, type, catalog, false);
     }
 
     protected Hashtable<UUID, List<SubscriptionBase>> createBundleSubscriptionMap(final SortedSet<BillingEvent> billingEvents) {
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
index 9b500aa..5c66e3c 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultBillingEvent.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -22,8 +24,6 @@ import java.util.List;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
@@ -52,7 +52,6 @@ public class DefaultBillingEvent implements BillingEvent {
     private final BillingPeriod billingPeriod;
     private final SubscriptionBaseTransitionType type;
     private final Long totalOrdering;
-    private final DateTimeZone timeZone;
 
     private final List<Usage> usages;
 
@@ -60,7 +59,7 @@ public class DefaultBillingEvent implements BillingEvent {
     private final boolean isDisableEvent;
     private final PlanPhase nextPlanPhase;
 
-    public DefaultBillingEvent(final ImmutableAccountData account, final EffectiveSubscriptionInternalEvent transition, final SubscriptionBase subscription, final int billCycleDayLocal, final Currency currency, final Catalog catalog) throws CatalogApiException {
+    public DefaultBillingEvent(final EffectiveSubscriptionInternalEvent transition, final SubscriptionBase subscription, final int billCycleDayLocal, final Currency currency, final Catalog catalog) throws CatalogApiException {
 
         this.catalog = catalog;
 
@@ -87,7 +86,6 @@ public class DefaultBillingEvent implements BillingEvent {
         this.billingPeriod = getRecurringBillingPeriod(isActive ? nextPlanPhase : prevPlanPhase);
         this.type = transition.getTransitionType();
         this.totalOrdering = transition.getTotalOrdering();
-        this.timeZone = account.getTimeZone();
         this.usages = initializeUsage(isActive);
         this.isDisableEvent = false;
     }
@@ -96,7 +94,7 @@ public class DefaultBillingEvent implements BillingEvent {
                                final Plan plan, final PlanPhase planPhase, final BigDecimal fixedPrice,
                                final Currency currency,
                                final BillingPeriod billingPeriod, final int billCycleDayLocal,
-                               final String description, final long totalOrdering, final SubscriptionBaseTransitionType type, final DateTimeZone timeZone,
+                               final String description, final long totalOrdering, final SubscriptionBaseTransitionType type,
                                final Catalog catalog,
                                final boolean isDisableEvent) {
         this.catalog = catalog;
@@ -111,7 +109,6 @@ public class DefaultBillingEvent implements BillingEvent {
         this.description = description;
         this.type = type;
         this.totalOrdering = totalOrdering;
-        this.timeZone = timeZone;
         this.usages = initializeUsage(isActive);
         this.isDisableEvent = isDisableEvent;
         this.nextPlanPhase = isDisableEvent ? null : planPhase;
@@ -228,11 +225,6 @@ public class DefaultBillingEvent implements BillingEvent {
     }
 
     @Override
-    public DateTimeZone getTimeZone() {
-        return timeZone;
-    }
-
-    @Override
     public List<Usage> getUsages() {
         return usages;
     }
@@ -290,9 +282,6 @@ public class DefaultBillingEvent implements BillingEvent {
         if (subscription != null ? !subscription.equals(that.subscription) : that.subscription != null) {
             return false;
         }
-        if (timeZone != null ? !timeZone.equals(that.timeZone) : that.timeZone != null) {
-            return false;
-        }
         if (totalOrdering != null ? !totalOrdering.equals(that.totalOrdering) : that.totalOrdering != null) {
             return false;
         }
@@ -316,7 +305,6 @@ public class DefaultBillingEvent implements BillingEvent {
         result = 31 * result + (billingPeriod != null ? billingPeriod.hashCode() : 0);
         result = 31 * result + (type != null ? type.hashCode() : 0);
         result = 31 * result + (totalOrdering != null ? totalOrdering.hashCode() : 0);
-        result = 31 * result + (timeZone != null ? timeZone.hashCode() : 0);
         return result;
     }
 
diff --git a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
index 2bdf73a..9674c01 100644
--- a/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
+++ b/junction/src/main/java/org/killbill/billing/junction/plumbing/billing/DefaultInternalBillingApi.java
@@ -33,6 +33,7 @@ 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.BillingAlignment;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
@@ -208,7 +209,7 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                 overridenBCD = transition.getNextBillCycleDayLocal() != null ? transition.getNextBillCycleDayLocal() : overridenBCD;
                 final int bcdLocal = overridenBCD != null ?
                                      overridenBCD :
-                                     calculateBcdForTransition(catalog, bcdCache, baseSubscription, subscription, account, currentAccountBCD, transition);
+                                     calculateBcdForTransition(catalog, bcdCache, baseSubscription, subscription, currentAccountBCD, transition, context);
 
                 if (currentAccountBCD == 0 && !updatedAccountBCD) {
                     log.info("Setting account BCD='{}', accountId='{}'", bcdLocal, account.getId());
@@ -216,16 +217,16 @@ public class DefaultInternalBillingApi implements BillingInternalApi {
                     updatedAccountBCD = true;
                 }
 
-                final BillingEvent event = new DefaultBillingEvent(account, transition, subscription, bcdLocal, account.getCurrency(), catalog);
+                final BillingEvent event = new DefaultBillingEvent(transition, subscription, bcdLocal, account.getCurrency(), catalog);
                 result.add(event);
             }
         }
     }
 
-    private int calculateBcdForTransition(final Catalog catalog, final Map<UUID, Integer> bcdCache, final SubscriptionBase baseSubscription, final SubscriptionBase subscription, final ImmutableAccountData account, final int accountBillCycleDayLocal, final EffectiveSubscriptionInternalEvent transition)
+    private int calculateBcdForTransition(final Catalog catalog, final Map<UUID, Integer> bcdCache, final SubscriptionBase baseSubscription, final SubscriptionBase subscription, final int accountBillCycleDayLocal, final EffectiveSubscriptionInternalEvent transition, final InternalTenantContext internalTenantContext)
             throws CatalogApiException, AccountApiException, SubscriptionBaseApiException {
         final BillingAlignment alignment = catalog.billingAlignment(getPlanPhaseSpecifierFromTransition(catalog, transition), transition.getEffectiveTransitionTime());
-        return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, account.getTimeZone(), accountBillCycleDayLocal);
+        return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, internalTenantContext, accountBillCycleDayLocal);
     }
 
     private PlanPhaseSpecifier getPlanPhaseSpecifierFromTransition(final Catalog catalog, final EffectiveSubscriptionInternalEvent transition) throws CatalogApiException {
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
index e8f80d2..2d17bdc 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -560,7 +560,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
             return new DefaultBillingEvent(subscription, effectiveDate, true, plan, planPhase, fixedPrice,
                                            currency,
                                            billingPeriod, billCycleDay,
-                                           description, totalOrdering, type, tz, null, false);
+                                           description, totalOrdering, type, null, false);
 
         } catch (final CatalogApiException e) {
             Assert.fail("", e);
@@ -633,7 +633,7 @@ public class TestBlockingCalculator extends JunctionTestSuiteNoDB {
 
         public MockBillingEvent() {
             super(subscription1, clock.getUTCNow(), true, null, null, BigDecimal.ZERO, Currency.USD, BillingPeriod.ANNUAL,
-                  4, "", 3L, SubscriptionBaseTransitionType.CREATE, DateTimeZone.UTC, null, false);
+                  4, "", 3L, SubscriptionBaseTransitionType.CREATE, null, false);
         }
     }
 
diff --git a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
index 98252a9..e146464 100644
--- a/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
+++ b/junction/src/test/java/org/killbill/billing/junction/plumbing/billing/TestDefaultBillingEvent.java
@@ -189,7 +189,7 @@ public class TestDefaultBillingEvent extends JunctionTestSuiteNoDB {
         return new DefaultBillingEvent(sub, effectiveDate, true,
                                        shotgun, shotgunMonthly, BigDecimal.ZERO,
                                        Currency.USD, BillingPeriod.NO_BILLING_PERIOD, billCycleDay,
-                                       "Test Event 1", totalOrdering, type, DateTimeZone.UTC, null, false);
+                                       "Test Event 1", totalOrdering, type, null, false);
     }
 
     private MockPlanPhase createMockMonthlyPlanPhase(@Nullable final BigDecimal recurringRate,

NEWS 3(+3 -0)

diff --git a/NEWS b/NEWS
index d6374b1..001a636 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+0.18.7
+    See https://github.com/killbill/killbill/releases/tag/killbill-0.18.7
+
 0.18.6
     See https://github.com/killbill/killbill/releases/tag/killbill-0.18.6
 
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java b/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java
index d1bec8d..5c2a254 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/calculator/BillingStateCalculator.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -25,7 +27,6 @@ import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.UUID;
 
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ObjectType;
 import org.killbill.billing.account.api.ImmutableAccountData;
@@ -68,7 +69,7 @@ public class BillingStateCalculator {
     }
 
     public BillingState calculateBillingState(final ImmutableAccountData account, final InternalTenantContext context) throws OverdueException {
-        final SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForAccount(account.getId(), account.getTimeZone(), context);
+        final SortedSet<Invoice> unpaidInvoices = unpaidInvoicesForAccount(account.getId(), context);
 
         final int numberOfUnpaidInvoices = unpaidInvoices.size();
         final BigDecimal unpaidInvoiceBalance = sumBalance(unpaidInvoices);
@@ -83,7 +84,7 @@ public class BillingStateCalculator {
         final List<Tag> accountTags = tagApi.getTags(account.getId(), ObjectType.ACCOUNT, context);
         final Tag[] tags = accountTags.toArray(new Tag[accountTags.size()]);
 
-        return new BillingState(account.getId(), numberOfUnpaidInvoices, unpaidInvoiceBalance, dateOfEarliestUnpaidInvoice, account.getTimeZone(), idOfEarliestUnpaidInvoice, responseForLastFailedPayment, tags);
+        return new BillingState(account.getId(), numberOfUnpaidInvoices, unpaidInvoiceBalance, dateOfEarliestUnpaidInvoice, idOfEarliestUnpaidInvoice, responseForLastFailedPayment, tags);
     }
 
     // Package scope for testing
@@ -103,8 +104,8 @@ public class BillingStateCalculator {
         return sum;
     }
 
-    SortedSet<Invoice> unpaidInvoicesForAccount(final UUID accountId, final DateTimeZone accountTimeZone, final InternalTenantContext context) {
-        final Collection<Invoice> invoices = invoiceApi.getUnpaidInvoicesByAccountId(accountId, clock.getToday(accountTimeZone), context);
+    SortedSet<Invoice> unpaidInvoicesForAccount(final UUID accountId, final InternalTenantContext context) {
+        final Collection<Invoice> invoices = invoiceApi.getUnpaidInvoicesByAccountId(accountId, context.toLocalDate(clock.getUTCNow()), context);
         final SortedSet<Invoice> sortedInvoices = new TreeSet<Invoice>(new InvoiceDateComparator());
         sortedInvoices.addAll(invoices);
         return sortedInvoices;
diff --git a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
index 56db945..11481f9 100644
--- a/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
+++ b/overdue/src/main/java/org/killbill/billing/overdue/wrapper/OverdueWrapper.java
@@ -104,7 +104,7 @@ public class OverdueWrapper {
         final BlockingState blockingStateForService = api.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, context);
         final String previousOverdueStateName = blockingStateForService != null ? blockingStateForService.getStateName() : OverdueWrapper.CLEAR_STATE_NAME;
         final OverdueState currentOverdueState = overdueStateSet.findState(previousOverdueStateName);
-        final OverdueState nextOverdueState = overdueStateSet.calculateOverdueState(billingState, clock.getToday(billingState.getAccountTimeZone()));
+        final OverdueState nextOverdueState = overdueStateSet.calculateOverdueState(billingState, context.toLocalDate(clock.getUTCNow()));
 
         overdueStateApplicator.apply(effectiveDate, overdueStateSet, billingState, overdueable, currentOverdueState, nextOverdueState, context);
 
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/applicator/formatters/TestDefaultBillingStateFormatter.java b/overdue/src/test/java/org/killbill/billing/overdue/applicator/formatters/TestDefaultBillingStateFormatter.java
index 4894535..8a2746f 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/applicator/formatters/TestDefaultBillingStateFormatter.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/applicator/formatters/TestDefaultBillingStateFormatter.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -32,7 +34,7 @@ public class TestDefaultBillingStateFormatter extends OverdueTestSuiteNoDB {
     @Test(groups = "fast")
     public void testBalanceFormatting() throws Exception {
         final BillingState billingState = new BillingState(UUID.randomUUID(), 2, BigDecimal.TEN,
-                                                           new LocalDate(), DateTimeZone.UTC, UUID.randomUUID(),
+                                                           new LocalDate(), UUID.randomUUID(),
                                                            null, null);
         final DefaultBillingStateFormatter formatter = new DefaultBillingStateFormatter(billingState);
         Assert.assertEquals(formatter.getFormattedBalanceOfUnpaidInvoices(), "10.00");
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java b/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java
index a5db764..0ac1feb 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/calculator/TestBillingStateCalculator.java
@@ -82,7 +82,7 @@ public class TestBillingStateCalculator extends OverdueTestSuiteNoDB {
     @Test(groups = "fast")
     public void testUnpaidInvoices() {
         final BillingStateCalculator calc = createBSCalc();
-        final SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L, 0L), DateTimeZone.UTC, internalCallContext);
+        final SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L, 0L), internalCallContext);
 
         Assert.assertEquals(invoices.size(), 3);
         Assert.assertEquals(BigDecimal.ZERO.compareTo(invoices.first().getBalance()), 0);
@@ -92,14 +92,14 @@ public class TestBillingStateCalculator extends OverdueTestSuiteNoDB {
     @Test(groups = "fast")
     public void testSum() {
         final BillingStateCalculator calc = createBSCalc();
-        final SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L, 0L), DateTimeZone.UTC, internalCallContext);
+        final SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L, 0L), internalCallContext);
         Assert.assertEquals(new BigDecimal("110.0").compareTo(calc.sumBalance(invoices)), 0);
     }
 
     @Test(groups = "fast")
     public void testEarliest() {
         final BillingStateCalculator calc = createBSCalc();
-        final SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L, 0L), DateTimeZone.UTC, internalCallContext);
+        final SortedSet<Invoice> invoices = calc.unpaidInvoicesForAccount(new UUID(0L, 0L), internalCallContext);
         Assert.assertEquals(calc.earliest(invoices).getInvoiceDate(), now);
     }
 }
diff --git a/overdue/src/test/java/org/killbill/billing/overdue/config/TestCondition.java b/overdue/src/test/java/org/killbill/billing/overdue/config/TestCondition.java
index 99efef6..7eec4dd 100644
--- a/overdue/src/test/java/org/killbill/billing/overdue/config/TestCondition.java
+++ b/overdue/src/test/java/org/killbill/billing/overdue/config/TestCondition.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -54,11 +56,11 @@ public class TestCondition extends OverdueTestSuiteNoDB {
         final UUID unpaidInvoiceId = UUID.randomUUID();
 
         final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, new LocalDate(),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
         final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, BigDecimal.ZERO, new LocalDate(),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
         final BillingState state2 = new BillingState(new UUID(0L, 1L), 2, BigDecimal.ZERO, new LocalDate(),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
 
         Assert.assertTrue(!c.evaluate(state0, new LocalDate()));
         Assert.assertTrue(c.evaluate(state1, new LocalDate()));
@@ -76,11 +78,11 @@ public class TestCondition extends OverdueTestSuiteNoDB {
         final UUID unpaidInvoiceId = UUID.randomUUID();
 
         final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, new LocalDate(),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
         final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("100.00"), new LocalDate(),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
         final BillingState state2 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("200.00"), new LocalDate(),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
 
         Assert.assertTrue(!c.evaluate(state0, new LocalDate()));
         Assert.assertTrue(c.evaluate(state1, new LocalDate()));
@@ -100,11 +102,11 @@ public class TestCondition extends OverdueTestSuiteNoDB {
         final LocalDate now = new LocalDate();
 
         final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, null,
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
         final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("100.00"), now.minusDays(10),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
         final BillingState state2 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("200.00"), now.minusDays(20),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
 
         Assert.assertTrue(!c.evaluate(state0, now));
         Assert.assertTrue(c.evaluate(state1, now));
@@ -124,11 +126,11 @@ public class TestCondition extends OverdueTestSuiteNoDB {
         final LocalDate now = new LocalDate();
 
         final BillingState state0 = new BillingState(new UUID(0L, 1L), 0, BigDecimal.ZERO, null,
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD, new Tag[]{});
         final BillingState state1 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("100.00"), now.minusDays(10),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS, new Tag[]{});
         final BillingState state2 = new BillingState(new UUID(0L, 1L), 1, new BigDecimal("200.00"), now.minusDays(20),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.DO_NOT_HONOR, new Tag[]{});
+                                                     unpaidInvoiceId, PaymentResponse.DO_NOT_HONOR, new Tag[]{});
 
         Assert.assertTrue(!c.evaluate(state0, now));
         Assert.assertTrue(c.evaluate(state1, now));
@@ -151,16 +153,16 @@ public class TestCondition extends OverdueTestSuiteNoDB {
 
         final UUID objectId = new UUID(0L, 1L);
         final BillingState state0 = new BillingState(objectId, 0, BigDecimal.ZERO, null,
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD,
+                                                     unpaidInvoiceId, PaymentResponse.LOST_OR_STOLEN_CARD,
                                                      new Tag[]{new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF, objectType, objectId, clock.getUTCNow()),
                                                              new DescriptiveTag(UUID.randomUUID(), objectType, objectId, clock.getUTCNow())});
 
         final BillingState state1 = new BillingState(objectId, 1, new BigDecimal("100.00"), now.minusDays(10),
-                                                     DateTimeZone.UTC, unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS,
+                                                     unpaidInvoiceId, PaymentResponse.INSUFFICIENT_FUNDS,
                                                      new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF, objectType, objectId, clock.getUTCNow())});
 
         final BillingState state2 = new BillingState(objectId, 1, new BigDecimal("200.00"), now.minusDays(20),
-                                                     DateTimeZone.UTC, unpaidInvoiceId,
+                                                     unpaidInvoiceId,
                                                      PaymentResponse.DO_NOT_HONOR,
                                                      new Tag[]{new DefaultControlTag(ControlTagType.OVERDUE_ENFORCEMENT_OFF, objectType, objectId, clock.getUTCNow()),
                                                              new DefaultControlTag(ControlTagType.AUTO_INVOICING_OFF, objectType, objectId, clock.getUTCNow()),
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
index b0a42f3..953b902 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestAccountTimeline.java
@@ -65,6 +65,8 @@ public class TestAccountTimeline extends TestJaxrsBase {
         Assert.assertEquals(timeline.getBundles().size(), 1);
         Assert.assertEquals(timeline.getBundles().get(0).getSubscriptions().size(), 1);
         Assert.assertEquals(timeline.getBundles().get(0).getSubscriptions().get(0).getEvents().size(), 3);
+        Assert.assertNotNull(timeline.getInvoices().get(0).getBundleKeys());
+
         final List<EventSubscription> events = timeline.getBundles().get(0).getSubscriptions().get(0).getEvents();
         Assert.assertEquals(events.get(0).getEffectiveDate(), new LocalDate(2012, 4, 25));
         Assert.assertEquals(events.get(0).getEventType(), "START_ENTITLEMENT");

README.md 10(+10 -0)

diff --git a/README.md b/README.md
index 79fbc02..c810485 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,16 @@ You can find more information on [killbill.io](http://killbill.io).
 * [User guides](http://killbill.io/userguide/) (source in the [killbill-docs](https://github.com/killbill/killbill-docs) repo)
 * [Wiki](https://github.com/killbill/killbill/wiki)
 
+## Build
+
+Build is handled by Maven:
+
+```
+mvn clean install -DskipTests=true
+```
+
+Note: some third-party artifacts (such as metrics-guice) are released in Bintray. Make sure to follow the instructions [here](https://bintray.com/bintray/jcenter) (Set me up! button) to update your settings.xml.
+
 ## License
 
 Kill Bill is released under the [Apache license](http://www.apache.org/licenses/LICENSE-2.0).
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
index bcba397..d02731d 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -22,7 +22,6 @@ 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.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -33,7 +32,6 @@ import org.killbill.billing.catalog.api.PlanChangeResult;
 import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PlanSpecifier;
 import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
-import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseWithAddOns;
 import org.killbill.billing.subscription.api.user.SubscriptionAndAddOnsSpecifier;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.killbill.billing.subscription.api.user.SubscriptionBuilder;
@@ -57,10 +55,10 @@ public interface SubscriptionBaseApiService {
     public boolean cancelWithRequestedDate(DefaultSubscriptionBase subscription, DateTime requestedDate, CallContext context)
             throws SubscriptionBaseApiException;
 
-    public boolean cancelWithPolicy(DefaultSubscriptionBase subscription, BillingActionPolicy policy, DateTimeZone accountTimeZone, int accountBillCycleDayLocal, CallContext context)
+    public boolean cancelWithPolicy(DefaultSubscriptionBase subscription, BillingActionPolicy policy, int accountBillCycleDayLocal, CallContext context)
             throws SubscriptionBaseApiException;
 
-    public boolean cancelWithPolicyNoValidation(Iterable<DefaultSubscriptionBase> subscriptions, BillingActionPolicy policy, DateTimeZone accountTimeZone, int accountBillCycleDayLocal, InternalCallContext context)
+    public boolean cancelWithPolicyNoValidation(Iterable<DefaultSubscriptionBase> subscriptions, BillingActionPolicy policy, int accountBillCycleDayLocal, InternalCallContext context)
             throws SubscriptionBaseApiException;
 
     public boolean uncancel(DefaultSubscriptionBase subscription, CallContext context)
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 b7bb7e7..17e695d 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
@@ -31,7 +31,6 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalCallContext;
@@ -356,7 +355,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     }
 
     @Override
-    public void cancelBaseSubscriptions(final Iterable<SubscriptionBase> subscriptions, final BillingActionPolicy policy, final DateTimeZone accountTimeZone, int accountBillCycleDayLocal, final InternalCallContext context) throws SubscriptionBaseApiException {
+    public void cancelBaseSubscriptions(final Iterable<SubscriptionBase> subscriptions, final BillingActionPolicy policy, int accountBillCycleDayLocal, final InternalCallContext context) throws SubscriptionBaseApiException {
         apiService.cancelWithPolicyNoValidation(Iterables.<SubscriptionBase, DefaultSubscriptionBase>transform(subscriptions,
                                                                                                                new Function<SubscriptionBase, DefaultSubscriptionBase>() {
                                                                                                                    @Override
@@ -369,7 +368,6 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                                                                                                    }
                                                                                                                }),
                                                 policy,
-                                                accountTimeZone,
                                                 accountBillCycleDayLocal,
                                                 context);
     }
@@ -732,7 +730,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                             policy = planChangeResult.getPolicy();
                         }
                         // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
-                        changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy, null, null, -1, context);
+                        changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy, null, -1, context);
                     }
                     dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, plan.getPriceListName(), changeEffectiveDate, utcNow, true, context);
                     break;
@@ -751,7 +749,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                             policy = catalogInternalApi.getFullCatalog(true, true, context).planCancelPolicy(spec, utcNow);
                         }
                         // We pass null for billingAlignment, accountTimezone, account BCD because this is not available which means that dryRun with START_OF_TERM BillingPolicy will fail
-                        cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy, null, null, -1, context);
+                        cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy, null, -1, context);
                     }
                     dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, cancelEffectiveDate, utcNow, true, context);
                     break;
@@ -836,12 +834,12 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     }
 
     @Override
-    public int getDefaultBillCycleDayLocal(final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final PlanPhaseSpecifier planPhaseSpecifier, final DateTimeZone accountTimeZone, final int accountBillCycleDayLocal, final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException {
+    public int getDefaultBillCycleDayLocal(final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final PlanPhaseSpecifier planPhaseSpecifier, final int accountBillCycleDayLocal, final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException {
 
         try {
             final Catalog catalog = catalogInternalApi.getFullCatalog(true, true, context);
             final BillingAlignment alignment = catalog.billingAlignment(planPhaseSpecifier, effectiveDate);
-            return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, accountTimeZone, accountBillCycleDayLocal);
+            return BillCycleDayCalculator.calculateBcdForAlignment(bcdCache, subscription, baseSubscription, alignment, context, accountBillCycleDayLocal);
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
index e4fd803..05c2133 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -18,11 +18,17 @@
 
 package org.killbill.billing.subscription.api.user;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -60,14 +66,9 @@ import org.killbill.clock.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.UUID;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 
 public class DefaultSubscriptionBase extends EntityBase implements SubscriptionBase {
 
@@ -261,8 +262,8 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
     }
 
     @Override
-    public boolean cancelWithPolicy(final BillingActionPolicy policy, final DateTimeZone accountTimeZone, int accountBillCycleDayLocal, final CallContext context) throws SubscriptionBaseApiException {
-        return apiService.cancelWithPolicy(this, policy, accountTimeZone, accountBillCycleDayLocal, context);
+    public boolean cancelWithPolicy(final BillingActionPolicy policy, int accountBillCycleDayLocal, final CallContext context) throws SubscriptionBaseApiException {
+        return apiService.cancelWithPolicy(this, policy, accountBillCycleDayLocal, context);
     }
 
     @Override
@@ -571,7 +572,7 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
         return getFutureEndDate() != null;
     }
 
-    public DateTime getPlanChangeEffectiveDate(final BillingActionPolicy policy, @Nullable final BillingAlignment alignment, @Nullable final DateTimeZone accountTimeZone, @Nullable final Integer accountBillCycleDayLocal, final InternalTenantContext context) {
+    public DateTime getPlanChangeEffectiveDate(final BillingActionPolicy policy, @Nullable final BillingAlignment alignment, @Nullable final Integer accountBillCycleDayLocal, final InternalTenantContext context) {
 
         final DateTime candidateResult;
         switch (policy) {
@@ -587,7 +588,7 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
                 } else {
 
                     // In certain path (dryRun, or default catalog START_OF_TERM policy), the info is not easily available and as a result, such policy is not implemented
-                    Preconditions.checkState(alignment != null && accountTimeZone != null && accountBillCycleDayLocal != null, "START_OF_TERM not implemented in dryRun use case");
+                    Preconditions.checkState(alignment != null && context != null && accountBillCycleDayLocal != null, "START_OF_TERM not implemented in dryRun use case");
 
                     Preconditions.checkState(alignment != BillingAlignment.BUNDLE || category != ProductCategory.ADD_ON,  "START_OF_TERM not implemented for AO configured with a BUNDLE billing alignment");
 
@@ -595,7 +596,7 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
                     // alignment purpose
                     Integer bcd = getBillCycleDayLocal();
                     if (bcd == null) {
-                        bcd = BillCycleDayCalculator.calculateBcdForAlignment(null, this, this, alignment, accountTimeZone, accountBillCycleDayLocal);
+                        bcd = BillCycleDayCalculator.calculateBcdForAlignment(null, this, this, alignment, context, accountBillCycleDayLocal);
                     }
 
                     final BillingPeriod billingPeriod = getLastActivePlan().getRecurringBillingPeriod();
@@ -604,7 +605,7 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
                         proposedDate = proposedDate.minus(billingPeriod.getPeriod());
                     }
 
-                    final LocalDate resultingLocalDate  = BillCycleDayCalculator.alignProposedBillCycleDate(proposedDate, bcd, billingPeriod, accountTimeZone);
+                    final LocalDate resultingLocalDate  = BillCycleDayCalculator.alignProposedBillCycleDate(proposedDate, bcd, billingPeriod, context);
                     candidateResult = context.toUTCDateTime(resultingLocalDate);
                 }
 
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 130a4ab..75b46b0 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -1,7 +1,7 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -29,7 +29,6 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.ReadableInstant;
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.ObjectType;
@@ -188,7 +187,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
             Preconditions.checkState(policy != BillingActionPolicy.START_OF_TERM, "A default START_OF_TERM policy is not availaible");
 
-            final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, null, null, -1, null);
+            final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, null, -1, null);
 
             return doCancelPlan(ImmutableMap.<DefaultSubscriptionBase, DateTime>of(subscription, effectiveDate), now, internalCallContext);
         } catch (final CatalogApiException e) {
@@ -210,18 +209,18 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
     @Override
-    public boolean cancelWithPolicy(final DefaultSubscriptionBase subscription, final BillingActionPolicy policy, final DateTimeZone accountTimeZone, int accountBillCycleDayLocal, final CallContext context) throws SubscriptionBaseApiException {
+    public boolean cancelWithPolicy(final DefaultSubscriptionBase subscription, final BillingActionPolicy policy, int accountBillCycleDayLocal, final CallContext context) throws SubscriptionBaseApiException {
         final EntitlementState currentState = subscription.getState();
         if (currentState == EntitlementState.CANCELLED) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
         }
 
         final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
-        return cancelWithPolicyNoValidation(ImmutableList.<DefaultSubscriptionBase>of(subscription), policy, accountTimeZone, accountBillCycleDayLocal, internalCallContext);
+        return cancelWithPolicyNoValidation(ImmutableList.<DefaultSubscriptionBase>of(subscription), policy, accountBillCycleDayLocal, internalCallContext);
     }
 
     @Override
-    public boolean cancelWithPolicyNoValidation(final Iterable<DefaultSubscriptionBase> subscriptions, final BillingActionPolicy policy, final DateTimeZone accountTimeZone, final int accountBillCycleDayLocal, final InternalCallContext context) throws SubscriptionBaseApiException {
+    public boolean cancelWithPolicyNoValidation(final Iterable<DefaultSubscriptionBase> subscriptions, final BillingActionPolicy policy, final int accountBillCycleDayLocal, final InternalCallContext context) throws SubscriptionBaseApiException {
         final Map<DefaultSubscriptionBase, DateTime> subscriptionsWithEffectiveDate = new HashMap<DefaultSubscriptionBase, DateTime>();
         final DateTime now = clock.getUTCNow();
 
@@ -229,7 +228,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
             for (final DefaultSubscriptionBase subscription : subscriptions) {
                 final BillingAlignment billingAlignment = (subscription.getState() == EntitlementState.PENDING ? null : catalogInternalApi.getFullCatalog(true, true, context).billingAlignment(new PlanPhaseSpecifier(subscription.getLastActivePlan().getName(), subscription.getLastActivePhase().getPhaseType()), clock.getUTCNow()));
-                final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, billingAlignment, accountTimeZone, accountBillCycleDayLocal, context);
+                final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy, billingAlignment, accountBillCycleDayLocal, context);
                 subscriptionsWithEffectiveDate.put(subscription, effectiveDate);
             }
         } catch (final CatalogApiException e) {
@@ -327,7 +326,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         }
 
         if (policyMaybeNull != null) {
-            return subscription.getPlanChangeEffectiveDate(policyMaybeNull, null, null, -1, null);
+            return subscription.getPlanChangeEffectiveDate(policyMaybeNull, null, -1, null);
         } else if (requestedDateWithMs != null) {
             return DefaultClock.truncateMs(requestedDateWithMs);
         } else {
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCancel.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCancel.java
index 72dd488..4ed3a8f 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCancel.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiCancel.java
@@ -1,7 +1,9 @@
 /*
  * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -382,7 +384,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
         // Move ahead a bit abd cancel START_OF_TERM
         clock.addDays(5);
         testListener.pushExpectedEvent(NextEvent.CANCEL);
-        subscription.cancelWithPolicy(BillingActionPolicy.START_OF_TERM, accountData.getTimeZone(), accountData.getBillCycleDayLocal(), callContext);
+        subscription.cancelWithPolicy(BillingActionPolicy.START_OF_TERM, accountData.getBillCycleDayLocal(), callContext);
         assertListenerStatus();
 
         subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
@@ -409,16 +411,18 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
 
         // Cancel / Uncancel a few times to make sure this works and we end up on a stable state
         for (int i = 0; i < 3; i++) {
-            subscription.cancelWithPolicy(BillingActionPolicy.IMMEDIATE, null, -1, callContext);
+            subscription.cancelWithPolicy(BillingActionPolicy.IMMEDIATE, -1, callContext);
 
             subscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
             assertEquals(subscription.getState(), EntitlementState.PENDING);
 
+            testListener.pushExpectedEvents(NextEvent.UNCANCEL);
             subscription.uncancel(callContext);
+            assertListenerStatus();
         }
 
         // Now check we are on the right state (as if nothing had happened)
-        testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.UNCANCEL, NextEvent.UNCANCEL, NextEvent.UNCANCEL);
+        testListener.pushExpectedEvents(NextEvent.CREATE);
         clock.addDays(10);
         assertListenerStatus();
 
@@ -511,7 +515,7 @@ public class TestUserApiCancel extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(subscription.getState(), Entitlement.EntitlementState.PENDING);
         assertEquals(subscription.getStartDate().compareTo(startDate), 0);
 
-        subscription.cancelWithPolicy(BillingActionPolicy.IMMEDIATE, null, 1, callContext);
+        subscription.cancelWithPolicy(BillingActionPolicy.IMMEDIATE, 1, callContext);
 
         testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.CANCEL);
         clock.addDays(5);
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
index 968376a..6891b28 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiError.java
@@ -157,7 +157,7 @@ public class TestUserApiError extends SubscriptionTestSuiteNoDB {
 
         subscription = subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext);
 
-        subscription.cancelWithPolicy(BillingActionPolicy.END_OF_TERM, null, -1, callContext);
+        subscription.cancelWithPolicy(BillingActionPolicy.END_OF_TERM, -1, callContext);
         try {
             subscription.changePlanWithDate(new PlanSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME), null, clock.getUTCNow(), callContext);
         } catch (final SubscriptionBaseApiException e) {
diff --git a/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java b/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
index aaa544b..d53a0a9 100644
--- a/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
+++ b/util/src/main/java/org/killbill/billing/util/bcd/BillCycleDayCalculator.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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
@@ -23,12 +23,11 @@ import java.util.UUID;
 import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
+import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.catalog.api.BillingAlignment;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.subscription.api.SubscriptionBase;
-import org.killbill.clock.ClockUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,17 +35,17 @@ public abstract class BillCycleDayCalculator {
 
     private static final Logger log = LoggerFactory.getLogger(BillCycleDayCalculator.class);
 
-    public static int calculateBcdForAlignment(@Nullable final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final BillingAlignment alignment, final DateTimeZone accountTimeZone, final int accountBillCycleDayLocal) {
+    public static int calculateBcdForAlignment(@Nullable final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final SubscriptionBase baseSubscription, final BillingAlignment alignment, final InternalTenantContext internalTenantContext, final int accountBillCycleDayLocal) {
         int result = 0;
         switch (alignment) {
             case ACCOUNT:
-                result = accountBillCycleDayLocal != 0 ? accountBillCycleDayLocal : calculateOrRetrieveBcdFromSubscription(bcdCache, subscription, accountTimeZone);
+                result = accountBillCycleDayLocal != 0 ? accountBillCycleDayLocal : calculateOrRetrieveBcdFromSubscription(bcdCache, subscription, internalTenantContext);
                 break;
             case BUNDLE:
-                result = calculateOrRetrieveBcdFromSubscription(bcdCache, baseSubscription, accountTimeZone);
+                result = calculateOrRetrieveBcdFromSubscription(bcdCache, baseSubscription, internalTenantContext);
                 break;
             case SUBSCRIPTION:
-                result = calculateOrRetrieveBcdFromSubscription(bcdCache, subscription, accountTimeZone);
+                result = calculateOrRetrieveBcdFromSubscription(bcdCache, subscription, internalTenantContext);
                 break;
         }
         return result;
@@ -70,16 +69,16 @@ public abstract class BillCycleDayCalculator {
         return new LocalDate(proposedDate.getYear(), proposedDate.getMonthOfYear(), proposedBillCycleDate, proposedDate.getChronology());
     }
 
-    public static LocalDate alignProposedBillCycleDate(final DateTime proposedDate, final int billingCycleDay, final BillingPeriod billingPeriod, final DateTimeZone accountTimeZone) {
-        final LocalDate proposedLocalDate = ClockUtil.toLocalDate(proposedDate, accountTimeZone);
+    public static LocalDate alignProposedBillCycleDate(final DateTime proposedDate, final int billingCycleDay, final BillingPeriod billingPeriod, final InternalTenantContext internalTenantContext) {
+        final LocalDate proposedLocalDate = internalTenantContext.toLocalDate(proposedDate);
         final LocalDate resultingLocalDate = alignProposedBillCycleDate(proposedLocalDate, billingCycleDay, billingPeriod);
         return resultingLocalDate;
     }
 
-    private static int calculateOrRetrieveBcdFromSubscription(@Nullable final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final DateTimeZone accountTimeZone) {
+    private static int calculateOrRetrieveBcdFromSubscription(@Nullable final Map<UUID, Integer> bcdCache, final SubscriptionBase subscription, final InternalTenantContext internalTenantContext) {
         Integer result = bcdCache != null ? bcdCache.get(subscription.getId()) : null;
         if (result == null) {
-            result = calculateBcdFromSubscription(subscription, accountTimeZone);
+            result = calculateBcdFromSubscription(subscription, internalTenantContext);
             if (bcdCache != null) {
                 bcdCache.put(subscription.getId(), result);
             }
@@ -87,11 +86,11 @@ public abstract class BillCycleDayCalculator {
         return result;
     }
 
-    private static int calculateBcdFromSubscription(final SubscriptionBase subscription, final DateTimeZone accountTimeZone) {
+    private static int calculateBcdFromSubscription(final SubscriptionBase subscription, final InternalTenantContext internalTenantContext) {
         final DateTime date = subscription.getDateOfFirstRecurringNonZeroCharge();
-        final int bcdLocal = ClockUtil.toDateTime(date, accountTimeZone).getDayOfMonth();
-        log.debug("Calculated BCD: subscriptionId='{}', subscriptionStartDate='{}', accountTimeZone='{}', bcd='{}'",
-                  subscription.getId(), date.toDateTimeISO(), accountTimeZone, bcdLocal);
+        final int bcdLocal = internalTenantContext.toLocalDate(date).getDayOfMonth();
+        log.debug("Calculated BCD: subscriptionId='{}', subscriptionStartDate='{}', bcd='{}'",
+                  subscription.getId(), date.toDateTimeISO(), bcdLocal);
         return bcdLocal;
     }
 }
diff --git a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
index badf00a..c7ba40e 100644
--- a/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
+++ b/util/src/test/java/org/killbill/billing/GuicyKillbillTestSuite.java
@@ -126,7 +126,9 @@ public class GuicyKillbillTestSuite {
         log.info("*** Starting test {}:{}", method.getDeclaringClass().getName(), method.getName());
         log.info("***************************************************************************************************");
 
-        internalCallContext.reset();
+        if (internalCallContext != null) {
+            internalCallContext.reset();
+        }
     }
 
     @AfterMethod(alwaysRun = true)
diff --git a/util/src/test/java/org/killbill/billing/mock/MockSubscription.java b/util/src/test/java/org/killbill/billing/mock/MockSubscription.java
index 5475050..c353b0d 100644
--- a/util/src/test/java/org/killbill/billing/mock/MockSubscription.java
+++ b/util/src/test/java/org/killbill/billing/mock/MockSubscription.java
@@ -1,7 +1,9 @@
 /*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 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:
  *
@@ -20,24 +22,22 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
-import org.killbill.billing.catalog.api.PlanSpecifier;
-import org.mockito.Mockito;
-
 import org.killbill.billing.catalog.api.BillingActionPolicy;
 import org.killbill.billing.catalog.api.BillingPeriod;
 import org.killbill.billing.catalog.api.Plan;
 import org.killbill.billing.catalog.api.PlanPhase;
+import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
+import org.killbill.billing.catalog.api.PlanSpecifier;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementSourceType;
 import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
-import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.killbill.billing.subscription.api.SubscriptionBase;
+import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseTransition;
 import org.killbill.billing.util.callcontext.CallContext;
+import org.mockito.Mockito;
 
 public class MockSubscription implements SubscriptionBase {
 
@@ -72,9 +72,9 @@ public class MockSubscription implements SubscriptionBase {
     }
 
     @Override
-    public boolean cancelWithPolicy(BillingActionPolicy policy, final DateTimeZone accountTimeZone, int accountBillCycleDayLocal, CallContext context)
+    public boolean cancelWithPolicy(BillingActionPolicy policy, int accountBillCycleDayLocal, CallContext context)
             throws SubscriptionBaseApiException {
-        return sub.cancelWithPolicy(policy, accountTimeZone, accountBillCycleDayLocal, context);
+        return sub.cancelWithPolicy(policy, accountBillCycleDayLocal, context);
     }
 
     @Override
diff --git a/util/src/test/java/org/killbill/billing/util/bcd/TestBillCycleDayCalculator.java b/util/src/test/java/org/killbill/billing/util/bcd/TestBillCycleDayCalculator.java
index 9fb4aed..4e0fb54 100644
--- a/util/src/test/java/org/killbill/billing/util/bcd/TestBillCycleDayCalculator.java
+++ b/util/src/test/java/org/killbill/billing/util/bcd/TestBillCycleDayCalculator.java
@@ -22,12 +22,15 @@ import java.util.UUID;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.killbill.billing.GuicyKillbillTestSuiteNoDB;
+import org.killbill.billing.account.api.Account;
 import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.account.api.ImmutableAccountData;
 import org.killbill.billing.catalog.api.BillingAlignment;
 import org.killbill.billing.catalog.api.Catalog;
 import org.killbill.billing.catalog.api.CatalogApiException;
 import org.killbill.billing.catalog.api.Plan;
+import org.killbill.billing.mock.MockAccountBuilder;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
 import org.killbill.billing.util.UtilTestSuiteNoDB;
@@ -57,7 +60,7 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
 
         final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
         Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
-        final Integer billCycleDayLocal = BillCycleDayCalculator.calculateBcdForAlignment(new HashMap<UUID, Integer>(), subscription, subscription, BillingAlignment.BUNDLE, account.getTimeZone(), 0);
+        final Integer billCycleDayLocal = BillCycleDayCalculator.calculateBcdForAlignment(new HashMap<UUID, Integer>(), subscription, subscription, BillingAlignment.BUNDLE, internalCallContext, 0);
 
         Assert.assertEquals(billCycleDayLocal, (Integer) expectedBCDUTC);
     }
@@ -68,6 +71,8 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
         final DateTime startDateUTC = new DateTime("2012-07-16T21:17:03.000Z", DateTimeZone.UTC);
         final int bcdLocal = 16;
 
+        createAccountAndRefreshTimeAwareContext(accountTimeZone, startDateUTC);
+
         verifyBCDCalculation(accountTimeZone, startDateUTC, bcdLocal);
     }
 
@@ -77,6 +82,8 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
         final DateTime startDateUTC = new DateTime("2012-07-16T21:17:03.000Z", DateTimeZone.UTC);
         final int bcdLocal = 16;
 
+        createAccountAndRefreshTimeAwareContext(accountTimeZone, startDateUTC);
+
         verifyBCDCalculation(accountTimeZone, startDateUTC, bcdLocal);
     }
 
@@ -86,6 +93,8 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
         final DateTime startDateUTC = new DateTime("2012-07-16T21:17:03.000Z", DateTimeZone.UTC);
         final int bcdLocal = 16;
 
+        createAccountAndRefreshTimeAwareContext(accountTimeZone, startDateUTC);
+
         verifyBCDCalculation(accountTimeZone, startDateUTC, bcdLocal);
     }
 
@@ -95,6 +104,8 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
         final DateTime startDateUTC = new DateTime("2012-07-16T21:17:03.000Z", DateTimeZone.UTC);
         final int bcdLocal = 17;
 
+        createAccountAndRefreshTimeAwareContext(accountTimeZone, startDateUTC);
+
         verifyBCDCalculation(accountTimeZone, startDateUTC, bcdLocal);
     }
 
@@ -104,6 +115,8 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
         final DateTime startDateUTC = new DateTime("2012-07-16T21:17:03.000Z", DateTimeZone.UTC);
         final int bcdLocal = 17;
 
+        createAccountAndRefreshTimeAwareContext(accountTimeZone, startDateUTC);
+
         verifyBCDCalculation(accountTimeZone, startDateUTC, bcdLocal);
     }
 
@@ -114,6 +127,8 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
         final DateTime startDate = new DateTime("2012-07-16T21:17:03.000Z", DateTimeZone.forID("HST"));
         final int bcdLocal = 17;
 
+        createAccountAndRefreshTimeAwareContext(accountTimeZone, startDate);
+
         verifyBCDCalculation(accountTimeZone, startDate, bcdLocal);
     }
 
@@ -125,7 +140,24 @@ public class TestBillCycleDayCalculator extends UtilTestSuiteNoDB {
         final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
         Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
 
-        final Integer bcd = BillCycleDayCalculator.calculateBcdForAlignment(new HashMap<UUID, Integer>(), subscription, subscription, BillingAlignment.SUBSCRIPTION, account.getTimeZone(), 0);
+        final Integer bcd = BillCycleDayCalculator.calculateBcdForAlignment(new HashMap<UUID, Integer>(), subscription, subscription, BillingAlignment.SUBSCRIPTION, internalCallContext, 0);
         Assert.assertEquals(bcd, (Integer) bcdLocal);
     }
+
+    private void createAccountAndRefreshTimeAwareContext(final DateTimeZone dateTimeZone, final DateTime referenceDateTime) throws AccountApiException {
+        final Account accountData = new MockAccountBuilder().externalKey(UUID.randomUUID().toString())
+                                                            .timeZone(dateTimeZone)
+                                                            .createdDate(referenceDateTime)
+                                                            .build();
+
+        GuicyKillbillTestSuiteNoDB.createMockAccount(accountData,
+                                                     accountUserApi,
+                                                     accountInternalApi,
+                                                     immutableAccountInternalApi,
+                                                     nonEntityDao,
+                                                     clock,
+                                                     internalCallContextFactory,
+                                                     callContext,
+                                                     internalCallContext);
+    }
 }
diff --git a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteNoDB.java b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteNoDB.java
index ad802db..920e5cb 100644
--- a/util/src/test/java/org/killbill/billing/util/UtilTestSuiteNoDB.java
+++ b/util/src/test/java/org/killbill/billing/util/UtilTestSuiteNoDB.java
@@ -25,6 +25,9 @@ import org.apache.shiro.mgt.SecurityManager;
 import org.apache.shiro.util.Factory;
 import org.apache.shiro.util.ThreadContext;
 import org.killbill.billing.GuicyKillbillTestSuiteNoDB;
+import org.killbill.billing.account.api.AccountInternalApi;
+import org.killbill.billing.account.api.AccountUserApi;
+import org.killbill.billing.account.api.ImmutableAccountInternalApi;
 import org.killbill.billing.security.Permission;
 import org.killbill.billing.security.api.SecurityApi;
 import org.killbill.billing.util.api.AuditUserApi;
@@ -63,6 +66,12 @@ public class UtilTestSuiteNoDB extends GuicyKillbillTestSuiteNoDB {
     protected SecurityApi securityApi;
     @Inject
     protected KillBillJndiLdapRealm killBillJndiLdapRealm;
+    @Inject
+    protected AccountUserApi accountUserApi;
+    @Inject
+    protected AccountInternalApi accountInternalApi;
+    @Inject
+    protected ImmutableAccountInternalApi immutableAccountInternalApi;
 
     @BeforeClass(groups = "fast")
     public void beforeClass() throws Exception {