背景

您可能会发现虽然每月的税前收入完全一致,扣除的 Income Tax 却有一些偏差。您可能遇到更换工作、工资调整、奖金发放、股票交付等,每月实际发放工资数额变化多端,不明如何验证工资条上的扣除,不知下月税后收入几何。

网上有许多的 Income Tax / National Insurance 计算器,比如 MSE 的这个gov.uk 的这个which.co.uk 的这个,以及一些较为复杂的比如 listentotaxman.comthesalarycalculator.co.uk 等。它们能根据年收入大致给出 Income Tax 和 Nation Insurance 的计算,部分可以处理 Student Loan,偏门 Tax Code,Pension,Tax Relief 等,但很少有见能精确算出每月实际扣税的工具。

本文讨论如何精确计算 PAYE 系统实际扣除的 Income Tax 和 National Insurance 数额。本文讨论因收入数额和产生时间导致的复杂情况,不讨论税收居民身份、多份工作等因素来的复杂问题,不讨论 employer contribution,不讨论 Income 和 National Insurance 之外的扣除。

本文讨论的是 2020 年 6 月的情况。

在阅读本文之前,建议读者对 Income Tax、National Insurance、HMRC、PAYE、Tax Code、Tax Year 等基本概念有所了解,或在专业人士的陪同下观看。如不具备认读代码的能力,可以跳过相关部分。

在阅读本文之后,同学们应当能够掌握根据中税前收入和本税年已缴纳数额计算出与 payslip 中结果分毫不差的应缴 Income Tax / National Insurance 的技能。

应缴 National Insurance

National Insurance 的法律基础是 Social Security Contributions and Benefits Act 1992 。该法律规定了:

  • National Insurance contributions 分为 Class 1、Class 1A、Class 1B、Class 2、Class 3、Class 4
  • Class 1 contribution 分为 primary(employee)和 secondary(employer)
  • Primary Class 1 National Insurance contribution 分 main primary percentage 和 additional primary percentage 两档征收
  • 每个 tax year 应当设有 lower earnings limit、primary threshold 和 upper earnings limit
  • 对于 Primary Class 1 National Insurance contribution,每个 tax week 中收入不足 lower earnings limit 的部分无需缴纳,且不积攒缴纳记录;超过 lower earnings limit 但不足 primary threshold 的无需缴纳,但积攒缴纳记录;超过 primary threshold 不足 upper earnings limit 的按 main primary percentage 缴纳,积攒缴纳记录;超过 upper earnings limit 的按 additional primary percentage 缴纳,积攒缴纳记录
  • 应缴 National Insurance 的计算方法
  • 一些其他东西

目前的 main primary percentage 和 additional primary percentage 由 National Insurance Contributions Act 2011 以对 Social Security Contributions and Benefits Act 1992 进行修订的形式确定,分别为 12% 和 2%。

目前的 limit 和 threshold 们由 The Social Security (Contributions) (Rates, Limits and Thresholds Amendments and National Insurance Funds Payments) Regulations 2020 以对 Social Security (Contributions) Regulations 2001 的修订的形式确定。目前的 lower earnings limit 为 £120,primary threshold 为 £183,upper earnings limit 为 £962。

实现如下:

1
2
3
4
5
6
7
niPayable :: Double -> Double
niPayable income =
    if income <= 183
    then 0.0
    else if income <= 962
    then (income - 183) * 0.12
    else (income - 962) * 0.02 + (962 - 183) * 0.12

我们可以制作这样一套算计器:

1
2
3
4
evaluator :: [Double] -> [Double] -> Double -> Double
evaluator rates limits income =
    sum $ zipWith (*) rates $ snd $
    mapAccumL (\income limit -> (max 0 (income - limit), min income limit)) income limits

使用算计器可以简化为:

1
2
3
niPayable' = evaluator
    [0, 0.12, 0.02] 
    [183, 779, 1/0]

灰常的简单。这样我们就知道了每周应缴的 NI。

您也许会问,如果这周横跨了两个 tax year 且它们的 rates / limits 不一致应当如何计算呢?Social Security Contributions and Benefits Act 1992 在 Section 122 中给出了 tax week 的定义:

“tax week” means one of the successive periods in a tax year beginning with the first day of that year and every seventh day thereafter, the last day of a tax year (or, in the case of a tax year ending in a leap year, the last two days) to be treated accordingly as a separate tax week;

据此,tax week 被定义为自一个 tax year 的第一天(包括)数起的七天周期,其中第 53 周只包含次年 4 月 5 日一天,在闰年时只包含 4 月 4 日和 5 日两天。在该定义下,一个 tax week 并不会横跨多个 tax year。

可是事情真的这么简单吗?

如果我们打开 gov.uk 上的 Rates and thresholds for employers 2020 to 2021 。其中的 thresholds 表给出了每周每月和每年三个尺度的数据,仔细观赏可发现它们之间的比例关系十分神奇。同一 threshold 的年月周数字与实际天数不成比例,如 lower earnings limit 每年是每周的 52 倍整,但一年比 52 周多一两天。更神奇的是不同 threshold 之间这个比例是不同的,如 primary threshold 每年约是每周的 51.9 倍。

这又是怎么一回事呢!

我们回去细读 The Social Security (Contributions) Regulations 2001 ,在 Section 10 Earnings limits and thresholds 的屁股后面还有一条 Section 11 强行等价 :如果按月发钱就用这个定制小数字按月算,按年发钱就用另一个定制小数字按年算。而这几个数字正是我们在 gov.uk 上看到的那几个。把数字换换我们就能知道该怎么算啦!

可是事情真的这么简单吗?

噢,在 Section 11 强行等价 的屁股后面还有 Section 12 Calculation of earnings-related contributions 。其中 12 (1) (b) 讲到:

as regards the calculation referred to in sub-paragraph (a) primary and secondary Class 1 contributions shall be calculated to the nearest penny and any amount of a halfpenny or less shall be disregarded.

思考五秒,大声说出来,这是什么舍入方法?

说四舍五入的拖出去打死。

好的,如果您还没死,稍稍的改一改,加个舍入即可。

1
niPayable'' = (/100) . fromIntegral . round . (*100) . niPayable

可是事情真的这么简单吗?

好像,是的?

应缴 Income Tax

Income Tax 的基本框架由 Income Tax Act 2007 确立。该法律规定了:

  • Income Tax 分为 basic rate、higher rate 和 additional rate 三档征收
  • 大部分人员享受 personal allowance,即事实上低于 basic rate 的一档
  • Personal allowance 可随收入增加而缩减
  • 应缴 Income Tax 的计算方法
  • 一些其他东西

三档的具体税率、具体的适用额度和 personal allowance 的额度,它们由通常年年焕新的 Finance Act 以对 Income Tax Act 2007 进行修订的形式确定。目前,2020 年的 Finance Bill 2019-21 尚未通过,最新的生效文件是 Finance Act 2019

注意不同于 National Insurance,应缴 Income Tax 在定义上取决于整个 Tax Year(4月6日至次年4月5日)的收入。如果您在某 Tax Year 的中间遇到了工资调整,应缴纳数额应按照整个 Tax Year 的收入计算,而不是每月分别计算,即并不存在每月或每周应缴纳数额的概念。可是到了 Tax Year 最后再收税将导致国家和个人的收入在时间上的不均匀分布,税务机关和财务部门工作负荷在时间上的不均匀分布,甚至可能因为钱被花光了收不上来,给税务机关工作人员的心灵造成创伤。因此,PAYE 会在每个发钱周期依据当前对本 Tax Year 总收入的预期和已缴纳数目作出扣除。

目前的规则是:

  • Personal allowance = £12,500
  • Basic rate = 20%; limit = £37,500
  • Higher rate = 40%; limit = £150,000
  • Additional rate = 45%
  • 收入超过 £100,000 时,每超过 £1 没收 £0.5 的 personal allowance

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
allowance :: Double -> Double
allowance income =
    if income < 100000
    then 12500
    else max 0 $ 12500 - (income - 100000) * 0.5

itPayable :: Double -> Double
itPayable income =
    if income <= allowance income
    then 0.0
    else if income <= allowance income + 37500
    then (income - allowance income) * 0.2 + allowance income * 0.0
    else if income <= allowance income + 37500 + 150000
    then (income - allowance income - 37500) * 0.4 + 37500 * 0.2 + allowance income * 0.0
    else (income - allowance income - 150000) * 0.45 + (150000 - 37500) * 0.4 + 37500 * 0.2 + allowance income * 0.0

使用之前的算计器简化得:

1
2
3
itPayable' = evaluator
    [0, 0.2, 0.4, 0.6, 0.4, 0.45]
    [12500, 37500, 50000, 25000, 25000, 1/0]

这一形式显示了 [100,000, 125,000] 收入范围内的边际税率是 60%。

现在我们可以轻松地通过一个 tax year 的总收入计算出应缴 Income Tax,可是怎么知道我在一个 tax year 里的总收入呢?如果我和公司约定了确定的年薪,2019-20 tax year 比 2020-21 tax year 多一天,2019-20 tax year 的总收入是否就更多呢?如果按月领取工资的我在 2020 年 4 月获得了涨薪,是否要将变化的工资拆开分配到两个 tax year 中计算呢?如果我三月的奖金在四月底下发,应当算作哪一 tax year 呢?

Income Tax (Earnings and Pensions) Act 2003 16 (4) 说了:言之有理即可

这里有一个小瑕疵,据 Income Tax Act 2007 35 (3) 规定,部分没收后的剩余 personal allowance 应当向上取整。这也就是我们日常生活中常见的另一种表述方式“年收入超过 £100,000 部分,每超过 £2 没收 £1 的 personal allowance”。但考虑这一点将导致计算结果不再连续,算计器的模型不再适用,所以我们在上面的实现中忽略了这个小误差。看到这里,读者也许会问,本文的目的不是探究如何“精确计算”吗?这部分误差并不小于 1p,为什么可以忽略呢?下面我们将会解释这个问题。

实扣 Income Tax

微小的差别

上面是我基于对规则的理解给出了算法的实现。但是,如果对比各种 Income Tax Calculator,我们会发现结果有些不一样:

Income listen to taxman gov.uk MSE 我们和 which
10,000 0.00 0.00 0 0.00
30,000 3,498.20 3,498.20 3,498 3,500.00
60,000 11,496.40 11,496.40 11,496 11,500.00
120,000 39,496.40 需要 tax code 39,496 39,500.00
180,000 66,000.00 需要 tax code 66,000 66,000.00

仔细观察后我们发现当且仅当输入在 (12,500, 125,018) 范围内时结果不同,而这个范围似乎是开始缴税到 personal allowance 归零的收入范围,容易猜得是 personal allowance 的问题。又经仔细研究,发现各大计算器不约而同地将 personal allowance 定为 £12,509 而不是我们在规定中看到的 £12,500。据此,我们得到了如下版本的计算方式:

1
2
3
itPayable'' = evaluator
    [0, 0.2, 0.4, 0.6, 0.4, 0.45]
    [12509, 37500, 49991, 25018, 24982, 1/0]

该版本计算结果与 listentotaxman、MSE 保持了一致。可是,为什么是 £12,509 呢?

有人认为这是因为 tax code 是 PAYE 决定 personal allowance 的唯一依据,而 tax code 的编码方式决定了 personal allowance 的最后一位会被擦除,如默认 12,500 的 personal allowance 对应 tax code 1250L,这样 HMRC 看不出最后一位是多少,于是本着不多扣的原则当成最大的 9(由于上面提到的舍入规则,personal allowance 理论值必然为整数)。

手动计算表

要解决“实际如何计算”的问题,我们可以效仿古人,根据手动计算流程进行操作。为此,HMRC 提供了 Tax pay tables: manual method

根据计算表中的说明,我们需要

  1. 算出 taxable pay
    1. 确定本周期的税前收入
    2. 加上本 tax year 之前已获得的收入
    3. 减去 1993 年的 Tables A 给出的扣除数
    4. 向下取整
  2. 算出 income tax
    1. 从第 4 页的格读出当前 tax year 至当前 tax month 的 basic rate limit
    2. 如不超过 basic rate limit,从 Table B 读出最终数字
    3. 如超过,从 Table C1 读出当前 tax year 至当前 tax month 的 basic rate limit + higher rate limit
    4. 如不超过 basic rate limit + higher rate limit,从 Table C1 读出 basic rate limit * basic rate,加上 Table D1 中读出的结果,得到最终数字
    5. 如超过 higher rate limit,从 C2 读出 basic rate limit * basic rate + higher rate limit * higher rate,加上 Table D2 中读出的结果,得到最终数字
  3. 如果算出来需要扣除的数字超过收入的 50%,应当暂缓扣除并拨打指定客服热线寻求帮助。

从这里我们能够发现:

  • 读表好麻烦。
  • 读表不涉及乘除法,几乎不会有舍入问题。
  • 实际使用的 personal allowance 由 Pay Adjustment Tables 定义。
  • 舍入方式是对 taxable pay 向下取整而不是对 income tax 的计算结果进行舍入。
  • 这个计算方法是 cumulative 的。我们每次都对整个 tax year 到目前为止的情况进行重新计算。在每月收收入数额不同的情况下,这种方式能使我们逐渐接近理论结果。
  • 存在 50% 的 regulatory limit。
  • Personal allowance、basic rate limit、higher rate limit 均被平均分配到了每个发钱周期。
  • 从 taxable pay 得到结果的方式与我们在应缴 Income Tax 部分提到的方法完全一致。
  • Basic rate limit 和 higher rate limit 的数额与我们在应缴 Income Tax 部分提到的完全一致。
  • 实际使用的 personal allowance 不是 £12,500 也不是 £12,509,而是 £12,509.16。

但是,Taxable pay tables: manual method 中只讲解了如何计算本税年至今为止应当扣除的 income tax,并没有明确说明当前周期需要扣除多少。PAYE Manual 简要地指出了雇主会扣除差额,如已经缴纳的多余应当扣除的,雇主会退款。

好用的计算器

现在我们知道了如何根据表格进行计算,也知道了 Tables B / C / D 事实上是对前文应缴 Income Tax 部分规则的另一种表示,但我们不知道 £12,509.16 从何而来,我们的计算还依赖着 Tables A。

虽然通过观察不难发现 Tables A 中的数值也是平均分摊到每月的,但是具体数字则显得毫无规律。从良心出发我们希望这个表格也是某种算法的一种表示,可这些数字着实令人摸不着头脑。

经过一番探索,我们发现 HMRC 的这款 PAYE Tax Calculator 十分好用,能够计算每月的扣除并给出符合 £12,509.16 的计算结果。于是我们尝试研究它的原理,却发现它粗暴地将表单 POST 出去,将数据写进 session 并不带参数地 302 到了结果页面。那里的计算结果是服务端渲染的,本地没有发现计算逻辑。

众所周知,HMRC 是重度 GitHub 用户,在它的 GitHub 上公开了近千个 repository。那么其中有没有这个好用的计算器呢?搜索 “calculator” 很容易就能找到 paye-tax-calculator-frontend 这个仓库。可是光有 frontend 有什么用?看 README 这个东西需要 “MongoDB 3.2 or later version”。虽然不知道一个计算器要 mongo 干什么但这样看来这应该不止是个 frontend,可能名字是瞎写的吧。经过仔细分析后,我们确定这真™只是个 frontend。整个仓库里唯一出现 mongo 字样的文件叫做 README.md

不过这没有难倒我们,虽然我们不懂 Scala 但不难发现其中引入了 uk.gov.hmrc.calculator.Calculator 这个不属于本仓库的似乎是用来干活的东西。通过 Google 搜索这个包名或 GitHub 搜索 org:hmrc filename:Calculator 或观察依赖列表,我们找到了 tax-kalculator 这个项目,而其中的 Calculator.kt 正是被引入的包包。hmrc 鸡贼地使用了奇怪的拼写来干扰我们。其中的这个文件表明字母部分为 L / T 的 tax code 的 personal allowance 计算方式确实是把字母换成 9,而最终的 personal allowance 是在这儿算计的。我们只需理解这短短几行逻辑,即可破解 Adjustment Table 的奥秘!

完全理解后,我们不难发现,这套代码采用的 personal allowance 是 £12,509.00 而不是 £12,509.16,而且它其实是本文开头提到的这个计算器的,而不是好用的计算器的。

又一番寻觅后我们依然没有发现好用的计算器的代码,但是另一个仓库 paye-estimator 中的这张代码揭晓了 £12,509.16 的由来:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class PAYEAllowanceSeedData(taxCodeNumber: BigDecimal) {
  val recalculatedTaxCodeNumber: BigDecimal = taxCodeNumber - 1
  val initQuotient:              Int        = (recalculatedTaxCodeNumber / 500).intValue()
  val initRemainder:             BigDecimal = recalculatedTaxCodeNumber % 500
  val middleRemainder:           BigDecimal = ((initRemainder + 1) * 10) + 9
}

class AnnualAllowance(taxCode: String, taxCodeNumber: BigDecimal) extends Allowance with TaxCalculatorHelper {
  override val quotient  = Money(0)
  override val remainder = Money(0)
  override val allowance: Money = if (taxCode.matches("([0]{1}[L-N,l-n,T,t,X,x]{1}){1}")) {
    Money(0)
  } else {
    (Money(taxCodeNumber) * 10) + 9
  }
}

class MonthlyAllowance(payeSeedData: PAYEAllowanceSeedData) extends Allowance {
  override val quotient  = Money(payeSeedData.initQuotient * 416.67)
  override val remainder = Money((payeSeedData.middleRemainder / 12).setScale(2, RoundingMode.UP))
  override val allowance: Money = quotient + remainder
}

class WeeklyAllowance(payeSeedData: PAYEAllowanceSeedData) extends Allowance {
  override val quotient  = Money(payeSeedData.initQuotient.*(96.16))
  override val remainder = Money((payeSeedData.middleRemainder / 52).setScale(2, RoundingMode.UP))
  override val allowance: Money = quotient.+(remainder)
}

我们可以看到 1250L 对应的 AnnualAllowance 依然是 £12,509,但 MonthlyAllowance 则为 £1,042.43,12 倍即为 £12,509.16。类似地,WeeklyAllowance 为 £240.57,52 倍则为 £12,509.64。因此,不同的发薪周期能够影响 personal allowance 的实际数额并影响实际扣除的 income tax,尽管最终实际扣除 income tax 的差距不会超过 20p。

这时,细心的小朋友就要问了,我们前面讲过一年严格地有 53 的 tax week,为什么这里使用 52 呢?我们来看看实际操作中如何处理。Pay Adjustment Tables Tables A 在第 56 页写道:

Weekly, fortnightly or 4 weekly pay day on 5 April or, in a leap year, on 4 or 5 April.

If there are 53 weekly, 27 fortnightly or 14 4 weekly pay days because the last pay day in the year falls on 5 April or in a leap year, on 4 or 5 April, follow the appropriate instructions in the Employer Further Guide to PAYE and NICs (help book CWG2) – available on line at www.gov.uk

我们按要求找到 最新的 Employer Further Guide to PAYE and NICs (help book CWG2),其中讲到:

Pay interval – weekly*

For the weekly pay interval the earnings period is weekly. To work out the National Insurance contributions, use either the appropriate weekly table or the exact percentage method to calculate National Insurance contributions.

When working out PAYE using tax tables A, if you’re using a code on a cumulative basis, use the table for the tax week that includes the date of payment. If a payday is in week 53, use the table for week 1 again on a non-cumulative basis.

If you’re using a code on a week 1 or month 1 basis, use the table for week 1 on each payday.

于是,一个避税小技巧似乎出现了。公司可以选择把年工资拆成 53 份,在每个 tax week 的第一天发,发完 week 53 后宣布更改发薪日到下一年的 tax week 的第一天。这样大家就有 £12,750.21 的 personal allowance 了!比起每月发钱至多可以少交 £96.42 呢!可惜,据这个这个说,HMRC 会发现多占了 personal allowance 并通过调整 tax code 的方式从下一 tax year 克扣 personal allowance。

重建 Pay Adjustment Tables

好,回到 £12,509.16,我们知道了这一数值背后的算法,就可以反过来猜测这一算法背后的设计考量了。注意以下条件均为猜测得到。

  • **条件1:**这个数字需要大于等于法定的 £12,500,这样对大部分人而言不会出现多扣,HMRC 也不需要花费大量资源处理退税问题。
  • **条件2:**由于 tax code 隐去了 personal allowance 的最后一位,这个数字必须大于等于 £12,509,这样对由于某些原因被调整 allowance 的人员不会出现多扣,HMRC 也不需要花费大量资源处理退税问题。
  • **条件3:**这个数字必须能被平均分摊到 12 个月,且每个月分到的数额必须是 0.01 的整数倍。这样我们有 £12,509.04、£12,509.16 等 8 个数字可选。
  • **条件4:**这个数字必须能够用来构造 Pay Adjustment Tables,方便手工计算。即需要存在 $k$ 和 $f$,使得:
    • $k$ 是 0.01 的非负整数倍;
    • 对于任意 $1 \leq x \leq 500$,$f(x)$ 总是 0.01 的非负整数倍。
    • 对于任意去掉最后一位的 tax code $x$(如 1,250),总有 $k\lfloor\frac{x-1}{500}\rfloor + f((x - 1)\ mod\ 500 + 1) \geq \frac{10x+9}{12}$。
  • **条件5:**这个数字必须尽可能小,这样不需要少收没有必要少收的税。

令 $x = 500a + b\ (a \geq 0, 1 \leq b \leq 500)$,有 $ka + f(b) \geq \frac{5000a + 10b + 9}{12}$,整理可得 $k \geq \frac{5000a + 10b + 9 - 12f(b)}{12a}$。

对于任意 $x$,即任意 $a$、$b$,上式均需满足。

固定 $b$,整理得 $k \geq \frac{5000}{12} + \frac{10b+9-12f(b)}{12a}$。

当 $a$ 足够大时,$\frac{10b+9-12f(b)}{12a}$ 趋近于零,因此有必要条件 $k \geq \frac{5000}{12}$。由于 $k$ 必须是 0.01 的整数倍,$k \geq 416.67$。

由于我们可以任意定义 $f$,可为每个可能的 $b$ 构造 $f(b)$ 使得 $10b + 9 -12f(b) \leq 0$。这样 $k \geq \frac{5000}{12} + \frac{10b+9-12f(b)}{12a}$ 在 $k=416.67$ 时可对任意 $a$、$b$ 成立。

由 $10b + 9 -12f(b) \leq 0$ 我们又可整理得到 $f(b) \geq \frac{10b+9}{12}$。取最小可得 $f(b) = \lceil\frac{10b+9}{12}\times 100\rceil \div 100$。

经验证,上述得出的 $k$ 和 $f$ 与 Pay Adjustment Tables 完全一致。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
k :: Double
k = 416.67

f :: Int -> Double
f b = (fromIntegral . ceiling) (fromIntegral (10 * b + 9) / 12 * 100) / 100

monthlyAllowance :: Int -> Double
monthlyAllowance taxCodePrefix =
    k * fromIntegral a + f (b + 1)
    where (a, b) = quotRem (taxCodePrefix - 1) 500

填坑

现在再来看一开始我们刚发现 £12,509 的时候给出的实现,我们其实做出了这样一个假设:多出来的 personal allowance 是完全白送的,而不是从 £37,500 的 basic rate limit 中扣走的。当时我们只通过与其他几个同样采用 £12,509 的计算器比较结果的方式初步验证了这一假设。但是它真的正确吗?对另外的 £0.16 也成立吗?

注意到 hmrc/tax-kalculator 的这条代码 采用的是 £12,509.00 的 allowance 和扣掉了 £50,000 的 basic rate 上界,也就是 £37,491 的 basic rate limit。在其中输入 £50,009 的年收入可以得到 £7,501.80 的 Income Tax。同样采用 £12,509.00 的 listentotaxman.com 却认为 basic rate limit 依然是 £37,500 并据此给出了 £7,500 的结果。

上面我们诸多结论的来源是手动计算表,那么根据该表,basic rate limit 并不会为多出的 allowance 作出抵消。因此,basic rate limit 应当保持 £37,500 不变。因此 hmrc/tax-kalculator 的实现是有瑕疵的。

多出的 personal allowance 也不会影响 personal allowance 开始缩减的 £100,000 和进入 additional rate 的 £150,000 两个点。因为 £100,000 在定义上与 personal allowance 的数额无关,而进入 additional rate 时 personal allowance 早已被扣完。

看到这里,我们也就能够解释上文提出的“为什么 personal allowance 的舍入规则可以忽略”的问题了。实际采用的 personal allowance 的精确数字是由 tax code 的前几位决定的,在最后一位上的舍入通常并不影响结果,即便产生了进位,对结果的影响也不是光考虑舍入可以解决的。当然,如果要计算理论上应缴的 Income Tax,还是应当考虑舍入。

同时,由于上一 tax year 的 personal allowance 必然为整数,taxable pay 也被向下取整,下一年的 personal allowance 若有调整也依然会是整数。这也解释了为什么我们只需要保证实际采用的 personal allowance 数值不小于 £12,509.00,而不是 £12,509.99。

实扣 National Insurance

相比 Income Tax,National Insurance 不是 cumulative 的,也没有变化的 allowance,事情就简单得多。可是看过了上面实扣 Income Tax 的部分,我们还是忍不住想再问一遍,NI 的事情真的那么简单吗?

不如依葫芦画瓢来验证一下。

诶怎么都不一样!这又是怎么回事呢?小编也不知道呢。

如果您按照手动计算表进行了操作,一定会发现这破表看起来就很不准。上来就先让抹掉 taxable income 后面的小数,直接导致法规里介绍的舍入规则毫无用武之地。表格里每 £4 才有一个数据点,也没有给出 0 - £4 范围的小表表。找不到就让向下取到表格里有的数,这一点倒是十分符合法规。他倒也很实诚,直接承认了不准:

The figures in the left-hand column of each table show steps between the LEL and the UEL/UST/ AUST. The NICs liability for each step is based on the earnings limits and percentage rates shown on page 6 and with the exception of the LEL, ST, PT, UEL, UST and AUST is worked out at the mid-point of the steps. Therefore, you and your employee may pay slightly more or less than if you used the exact percentage method to work out the NICs due.

也就是说,我们拿着 £3,087.88 这个数字,按要求砍掉零头变成 £3,087,去表格里找不到,按要求取了 £3,084 那行的数据,结果这个数据是根据 £3,086 算出来的???

不过吧,根据 12 (2) 表什么的都是 alternative,咱们会用电脑的乖孩子还是要走正道。

可是咱走出来的这个道还是和好用的计算器歪了 1p。怎么回事?怎么回事?

National Insurance guidance for software developers 中我们找到了解释:

As the law requires that £0.005 or less is disregarded, as a matter of policy we only look at the third decimal place in calculating NICs due where such calculation results in more than two decimal places.

「法规只说了 0.5p 及以下要舍去没说 0.5p 以上要进位 🤷‍♂️,所以 0.6p 以下统统舍去好了!」

很好,这样子我们的道就摆正了。

但是我们还是很好奇,官方指定的 exact percentage method 是个什么东西呢?正好 National Insurance guidance for software developers 中给出了计算方式,比如:

Earnings above LEL up to and including PT/ST

$$(GP - (\frac{LEL \times p}{w/m}))^\# - (GP - (\frac{PT/ST \times p^1}{w/m}))^\#$$

这是什么鬼东西!分数外面为什么要套括号!

花点时间仔细发现发现每个东西都是啥:

  • $GP$ 是 Gross Pay
  • $LEL$ 是 Lower Earnings Limit
  • $PT/ST$ 是 Primary Threshold / Secondary Threshold
  • 被套了括号的分数坨坨是实际采用的 limit / threshold
  • $p$ 表示本次发几周 / 几个月的钱
  • $p^1$ 就是 $p$,但一旦出现,分数坨坨的舍入规则就从向上取整改成向上取整
  • $w/m$ 表示一年有几周 / 几个月,且特别说明周数取 52 而不是 53
  • $(x)^\#$ 就是 $max(x, 0)$

我们可以看到 $GP$ 、$LEL$、$PT$、$ST$ 什么的都是一个东西而不是乘积,$PT/ST$、$w/m$ 也是一个东西而不是商。$p^1$ 的定义倒是十分符合数学上常见的意义可是为什么要重新定义一个符号来把分数坨坨的舍入规则从向上取整改成向上取整呢?

往前翻翻,噢原来在 2016-2017 版本中 这个符号的技能是把分数坨坨的舍入规则从 round to nearest pound 改成向上取整。

看到这里,聪明的小朋友一定已经发现了,其实 annual limits / thresholds 才是本体,怪不得看起来那么工整。而 weekly 和 monthly 的数据都是这个 exact percentage method 给出的,经过了舍入所以看起来比例不匀。

总结与思考

看到这里,相信小朋友们对 Income Tax 和 National Insurance 的计算已经有了初步的了解。我们知道了:

  • 除了 tax year,还存在 tax month 和 tax week。一个 tax year 严格有 12 个 tax month 和 53 个 tax week。
  • Monthly PAYE 实际采用的 personal allowance £12,509.16 大于法律规定的 £12,500。
  • Income Tax 在定义上取决于一个 tax year 的总收入,而 National Insurance 取决于一个发薪周期内的收入。这决定了 Income Tax 的计算是 cumulative 的,而 National Insurance 的不是。
  • 在总收入不变的情况下,领取收入的节奏和时机可能影响 PAYE 实际扣除的 Income Tax 和 National Insurance 的数额。
  • 应缴 Income Tax 与实扣 Income Tax 的区别主要体现在实际采用 personal allowance 的区别上。
  • 应缴 National Insurance 与实扣 National Insurance 的区别主要体现在舍入规则和(当发薪周期不规整时)实际采用的 threshold 和 limit 的数值上。
  • 实扣 National Insurance 有不止一种计算方式,可能产生不同的计算结果。

同时,我们也得到了一些新的问题。虽然这些问题并不影响我们对 PAYE 实际扣除数额的精确计算,但是如果您正好有相关的经验或想法,欢迎在下方留言交流。

  • 是否需要在 Tax Return 中补上由于 £12,509.16 而 “少缴” 的部分呢?
  • HMRC “少收” Income Tax 的法律依据是什么呢?这是不是违规操作导致了国有资产的流失呢?
  • 对于年收入超过 £100,000 的人员,实际操作中 personal allowance 的缩减是如何反映在 tax code 上的呢?
    • 通过某种方式预计该税年收入超过 £100,000,立即更换为 0T
    • 依据本税年实际已获得收入每月动态调整 tax code?
    • 某税年收入超过 £100,000,次年立即更换为 0T
  • 如果在 tax year 中间收入显著下滑导致某月起已缴纳的 income tax 大于应当扣除的,雇主是否会替 HMRC 垫付这部分退款呢?如果这部分数额巨大雇主无法垫付如何处理呢?
  • Taxable pay tables: manual method 提到了 50% 的 regulatory limit。但这 50% 是指本周期应扣除与本周期收入的比例还是当前税年目前应扣除与当前税年已产生收入的比例呢?
  • National Insurance 的手动计算表为什么要逐个列出所有数字而不是列出 0.01, 0.02, …, 1, 2, …, 10, 20, …, 100, 200, …, 1,000, 2,000, … 这样的序列由操作者自行求和呢?这样既可以少写几行,又可以更加精确。

习题

  • 30 岁的小明 2020 年 10 月参加工作,每月发薪,以下是他的收入情况。请问 2020-21 tax year 小明理论上应缴纳多少 Income Tax,多少 National Insurance?如果他获得 1250L tax code,每月 PAYE 会扣除多少 Income Tax,多少 National Insurance?
Tax Month Net Income
1 - 6 £0.00
7 £3,000.00 + £3,000.12(搬家费)
8 £3,000.00
9 £3,000.00 + £123.45(发型时髦,奖励 £123.45)
10 £20,000.00(试用期结束,工资上调)
11 £20,000.00 + £543.21(见义勇为,勇斗歹徒,奖励 £543.21)
12 £20,000.00
  • 30 岁的小张 2020 年 4 月参加工作,每月发薪,次月感染新冠不幸罹难,以下是他的收入情况。请问 2020-21 tax year 小明理论上应缴纳多少 Income Tax,多少 National Insurance?如果他获得 1250L tax code,在前三个 tax month 中每月 PAYE 会扣除多少 Income Tax,多少 National Insurance?
Tax Month Net Income
1 £8,000.80
2 £2,000.20
3 £900.00(未休假期)
4-12 £0.00
  • 以上两题有个瑕疵,你能找出是什么吗?(超纲)

  • 试实现 PAYE 每月实扣 Income Tax 的计算:

    1
    2
    
    itToDeduct :: Int -> Int -> Double -> Double -> Double
    itToDeduct taxMonth taxCodePrefix incomeYTD taxPaidYTD = error "not implemented"
    
  • 现有的 Pay Adjustment Tables 使用了 tax code 去掉最后一位后除以 500 的商和余数。

    • 能否保持 500 这个参数不变,制作一套 Pay Adjustment Tables 使 1250L 对应的 allowance 为 £1,2509.04?这样做会有什么问题?
    • 500 这个参数能否减小?能否任意减小?如果减小会有什么后果?能否增大?能否任意增大?如果增大会有什么后果?
  • 如果未来的某一天默认 personal allowance 调整为了 £12,500,000,能否继续沿用现在的系统?可能会有什么问题?

参考答案

略。