Tính thời gian làm việc thực tế (1 người xem)

  • Thread starter Thread starter le tin
  • Ngày gửi Ngày gửi
Liên hệ QC

Người dùng đang xem chủ đề này

le tin

Học mãi
Tham gia
22/10/07
Bài viết
722
Được thích
560
Chào các bạn
Tôi có bài toán về tìm thời gian thực tế như file đính kèm , mong có sự giúp đỡ
Cảm ơn
 

File đính kèm

Em xin góp một cách giải:
000-163.gif
Dựa vào dữ liệu của bác, em đặt 3 Name để kiểm tra dữ liệu ngày giờ như sau:
  • Test1 = Sheet1!F$4 + Sheet1!F$3/24
  • Test2 = (AND(HOUR(Test1)>11.5,HOUR(Test1)<13.5))*2/24 + (OR(HOUR(Test1)>17,HOUR(Test1)<7))*16.5/24
  • Test3 = (WEEKDAY(Test2+Test1)=7)*44/24 - (WEEKDAY(Sheet1!F$4)=7)*2/24
Công thức để tính thời gian dự kiến kết thúc (F5:H5)
= Test1 + Test2 + Test3​
Công thức để tính thời gian làm thực tế (F7:H7)
=(F6-F4)*24 - (AND(HOUR(F6)>13.5, HOUR(F4)<11.5)*2 + (INT(F6)-INT(F4))*16.5 + (WEEKDAY(F6)=2)*11)​
Nhờ bác kiểm tra lại giúp em xem có đúng hay không.

----------------------
BÀI NÀY CHƯA CHÍNH XÁC. XIN PHÉP GỠ BỎ FILE ĐÍNH KÈM.
BNTT.
 
Lần chỉnh sửa cuối:
Em xin góp một cách giải:
000-163.gif
Dựa vào dữ liệu của bác, em đặt 3 Name để kiểm tra dữ liệu ngày giờ như sau:
  • Test1 = Sheet1!F$4 + Sheet1!F$3/24
  • Test2 = (AND(HOUR(Test1)>11.5,HOUR(Test1)<13.5))*2/24 + (OR(HOUR(Test1)>17,HOUR(Test1)<7))*16.5/24
  • Test3 = (WEEKDAY(Test2+Test1)=7)*44/24 - (WEEKDAY(Sheet1!F$4)=7)*2/24
Công thức để tính thời gian dự kiến kết thúc (F5:H5)
= Test1 + Test2 + Test3​
Công thức để tính thời gian làm thực tế (F7:H7)
=(F6-F4)*24 - (AND(HOUR(F6)>13.5, HOUR(F4)<11.5)*2 + (INT(F6)-INT(F4))*16.5 + (WEEKDAY(F6)=2)*11)​
Nhờ bác kiểm tra lại giúp em xem có đúng hay không.
Bác Tường làm hay quá, khi nào Bác chỉ giúp tôi hàm hour này với. Bữa giờ xem mà không biết cách làm giúp Bác Le Tin.
Bác giải thích hộ số *44/24
Cám ơn Bác nhiều!
 
44 là số giờ từ 11:30 thứ bảy đến 7:30 sáng thứ 2
chia 24 là giờ quy ra ngày (học của ngocmaipretty), ngược lại nhân 24 là quy ngày ra giờ
nhân 44/24 là nếu WEEKDAY(Test2+Test1)=7) = "giờ kết thúc là nhằm vào thứ 7" thì cộng thêm 44 giờ

Giải thích hộ BNTT, nhưng hình như còn sai:
- test1 + test2 trúng ngày chủ nhật thì sao?
- test1 + test2 trúng ngày thứ bảy, nhưng vào buổi sáng thì sao?
- trừ 2 giờ để làm gì?

Chắc phải cầu cứu lại Ms. NgocMai!
 
Bác Tường làm hay quá, khi nào Bác chỉ giúp tôi hàm hour này với. Bữa giờ xem mà không biết cách làm giúp Bác Le Tin.
Bác giải thích hộ số *44/24
Cám ơn Bác nhiều!
Để em diễn Nôm cho bác nghe nhá. Trước tiên bác phải nắm được 2 cái này:
  • Khi muốn chuyển đổi một con số (1 tiếng, 2 tiếng rưỡi... kiểu nói) ra dạng thời gian cho Excel nó hiểu, thì mình chia cho 24. Bởi vì 1 giờ trong Excel có nghĩa là 1/24 (ngày), 12 giờ = 12/24 = nữa ngày.
  • Còn khi muốn chuyển một số ở dạng thời gian của Excel thành con số kiểu tiếng Việt, là làm ngược lại í, thì lại nhân cho 24. Bác xem công thức tính thời gian làm việc thực tế, em lại đi nhân cho 24 đó.

Test1 =Sheet1!F$4 + Sheet1!F$3/24
Lấy thời gian bắt đầu cộng với định mức quy định, để tính ra thời gian kết thúc (chưa tính giờ nghỉ, ngày nghỉ gì hết).
Do ở F3 đang là dạng con số, nên phải chia cho 24 để nó có thể cộng được với F4 (đang là dạng thời gian).
Tuy nhiên, kết quả này, còn phải cộng thêm giờ nghỉ trưa, giờ đi nhậu buổi chiều... cho nên phải có thêm cái Test 2.​


Test2 =(AND(HOUR(Test1)>11.5, HOUR(Test1)<13.5))*2/24 + (OR(HOUR(Test1)>17, HOUR(Test1)<7))*16.5/24

Mấy con số 11.5, 13.5, 17, 7 chắc bác đoán được là gì chớ?
Con số 2/24 (2 tiếng) chính là thời gian nghỉ buổi trưa (từ 11 giờ đến 13 giờ)
Con số 16.5/24 (16 tiếng rưỡi) là thời gian từ sau 5 giờ chiều cho đến 7 giờ sáng hôm sau.
Công thức này đem cái kết quả của Test1 đi dò, nếu rơi vào mấy khoảng thời gian nghỉ, thì phải cộng thêm tương ứng.
Nhưng cái công thức này cũng chưa chính xác, bởi nó chưa tính đến chuyện chiều thứ 7 thì đi Hòn đất chứ không đi làm, còn ngày Chủ Nhật thì nghỉ nguyên ngày, ở nhà... ngủ. Bởi thế nên mới có cái Test3.​


Test3 =(WEEKDAY(Test2+Test1)=7)*44/24 - (WEEKDAY(Sheet1!F$4)=7)*2/24

Cái này là cái em nhức đầu nhất. Phải hết chừng 2 điếu con mèo mới nghĩ ra cái trò kiểm tra kết quả của Test1 cộng với Test2, nếu nó rơi vào thứ 7, thì phải cộng thêm giờ làm chiều thứ 7 và ngày nghỉ CN...
Thế là em xòe ngón tay ra đếm: Ngày CN có 24 tiếng, ngày thứ Bảy làm có 4 tiếng buổi sáng à, vậy dư 20 tiếng, lấy 24+20 ra 44 tiếng. Bác hiểu con số 44 ở đâu ra rồi chứ.
Nhưng chưa hết, thứ Bảy thì nghỉ từ 11 giờ 30, đâu có nghỉ trưa, trong khi mình đã trừ cái chuyện nghỉ trưa ở Test2 rồi, nên phải thêm một chuyện, nếu như ngày bắt đầu làm là ngày thứ 7, thì phải trừ bớt đi 2 tiếng nghỉ trưa.​


Cuối cùng, cộng hết 3 cái Test này lại, là ra kết quả thời gian hoàn thành theo dự kiến.

Phù... khi chơi thì không thấy gì. Mà phải kể lại chuyện đã chơi như thế nào, sao mà nó khó thế!
 
44 là số giờ từ 11:30 thứ bảy đến 7:30 sáng thứ 2
chia 24 là giờ quy ra ngày (học của ngocmaipretty), ngược lại nhân 24 là quy ngày ra giờ
nhân 44/24 là nếu WEEKDAY(Test2+Test1)=7) = "giờ kết thúc là nhằm vào thứ 7" thì cộng thêm 44 giờ

Giải thích hộ BNTT, nhưng hình như còn sai:
- test1 + test2 trúng ngày chủ nhật thì sao?
- test1 + test2 trúng ngày thứ bảy, nhưng vào buổi sáng thì sao?
- trừ 2 giờ để làm gì?

Chắc phải cầu cứu lại Ms. NgocMai!
Hu hu... Đúng là chưa chính xác.
Bài này không dùng hàm HOUR được rồi! Vì Hour nó hổng tính được cái 30 phút!
Để đó, em sẽ làm lại. Chơi MOD chứ hổng chơi HOUR nữa. Cũng hông thèm cầu viện Ms. Ngọc Mai.
Nói với cái lão Cheettit là sau khi làm lại em sẽ tự xóa bài này.
 
Bài đã gửi hôm qua không chính xác. Xin thành thật cáo lỗi cùng bác Letin và bác ThuNghi. Em xin gửi lại bài khác:
000-163.gif
Em đặt lại 4 Name để kiểm tra dữ liệu ngày giờ như sau:
  • Test1: Dùng để tính nhẩm thời gian hoàn thành, chưa tính thời gian nghỉ và ngày nghỉ
    = Sheet1!F$4 + Sheet1!F$3/24

  • Test2: Dùng để tính thời gian nghỉ trưa (2 tiếng) và thời gian nghỉ tối (16.5 tiếng)
    = (AND(Test1-INT(Test1)>11.5/24, Test1-INT(Test1)<13.5/24))*2/24 + (OR(Test1-INT(Test1)>17/24, Test1-INT(Test1)<7.5/24))*16.5/24

  • Test3: Dùng để kiểm tra xem kết quả có rơi vào chiều thứ 7, hay vào Chủ Nhật hay không, và kiểm tra xem thời gian bắt đầu có phải là sáng thứ 7 hay không. Nếu có thì cộng thêm khoảng thời gian tương ứng.
    =OR(AND(WEEKDAY(Test2+Test1)=7, (Test2+Test1)-INT(Test2+Test1)>11.5/24), WEEKDAY(Test2+Test1)=1)*44/24 - AND(WEEKDAY(Sheet1!F$4)=7, (Test2+Test1)-INT(Test2+Test1)>11.5/24)*2/24

  • Test4: Dùng để kiểm tra xem kết quả cuối cùng có rơi vào trong giờ nghỉ trưa hoặc buổi tối hay không. Nếu có thì cộng thêm khoảng thời gian tương ứng.
    = IF((Test1+Test2+Test3)-INT(Test1+Test2+Test3)>17/24, 16.5/24, IF((Test1+Test2+Test3)-INT(Test1+Test2+Test3)>11.5/24, 2/24, 0))


Công thức để tính thời gian dự kiến kết thúc (F5:H5)
= Test1 + Test2 + Test3 + Test4


Công thức để tính thời gian làm thực tế (F7:H7) vẫn như cũ:
=(F6-F4)*24 - (AND(HOUR(F6)>13.5, HOUR(F4)<11.5)*2 + (INT(F6)-INT(F4))*16.5 + (WEEKDAY(F6)=2)*11)


Nhờ các bác kiểm tra lại giúp em xem có đúng hay không.
 

File đính kèm

Lần chỉnh sửa cuối:
Cảm ơn bạn BNTT ,nhưng chưa ổn ,Ví dụ nhập 41.5 thì phải cách đúng 1 tuần sau (vì 1 tuần làm 41.5 giờ) chứ
 
Cảm ơn bạn BNTT ,nhưng chưa ổn ,Ví dụ nhập 41.5 thì phải cách đúng 1 tuần sau (vì 1 tuần làm 41.5 giờ) chứ
Dạ đúng là như vậy. Chưa chính xác. Em đang nghiên cứu lại nó, vì quả thật là ... hơi khó nhai!
 
Phần tính ra thời gian dự định thì khó , mình chỉ mới có trong ý tưởng thôi
Ý định là : Cứ lấy thời gian bắt đầu cọng cho 3 (chẳng hạng vậy) , đến khi quá 11.30 thứ 7 thì cọng vào 40 để đến T2 , cho đến bằng hoặc quá Định mức thì dừng lại .
Không biết ý đó có giúp bạn đỡ đau đầu không ,(mình nghĩ ghi ra code có dễ hơn không ?)
Cảm ơn bạn
 
Dạ đúng là như vậy. Chưa chính xác. Em đang nghiên cứu lại nó, vì quả thật là ... hơi khó nhai!
Bài toán dạng này không phải là KHÓ, mà là CỰC KHÓ
Có 1 bài toán gần tương tự:
- Cho trước ngày bắt đầu
- Cho trước tổng số ngày
- Tính ngày kết thúc (trừ CN và các ngày nghĩ)

Hoặc 1 bài toán thuận:
- Cho trước giờ bắt đầu
- Cho trước giờ kết thúc
- Tính tổng số giờ làm việc (trừ các giờ nghĩ)

Nhưng bài tính thời gian của tác giã còn khó hơn ---> Khó ở điểm nó là 1 bài toán ngược... và các khoảng nghĩ nằm lung tung
Tuy nhiên các bạn cứ thử với bài toán về NGÀY, nếu làm ra thì đó là cơ sở để giãi quyết bài toán về GIỜ
 
Bài toán dạng này không phải là KHÓ, mà là CỰC KHÓ
Quả đúng là Cực Khó!
Em nghĩ rằng chắc không dùng công thức nổi, giả như có nổi đi nữa thì chắc cái công thức này sẽ dài khủng khiếp, và phải rất nhiều công thức thì mới có thể chơi nổi!
Em có ý tưởng này, dùng VBA. Nhưng em thì không giỏi về VBA, nên xin nêu ra ý tưởng thôi, các bác xem có khả thi không thì làm dùm...

Lấy thời gian bắt đầu + thời gian dự định sẽ hoàn thành công việc, ra kết quả là A chẳng hạn. Rồi dùng vòng lặp để kiểm tra kết quả A:
  • Nếu A rơi vào khoảng nghỉ trưa (tử 11:30 đến 13:30) thì cộng thêm 2 tiếng. Cho ra A1.
  • Nếu A1 rơi vào khoảng nghỉ chiều (từ 17:00 đến 7:30 ngày hôm sau) thì cộng thêm 14,5 tiếng. Cho ra A2.
  • Nếu A2 rơi vào trưa thứ 7 (sau 11:30) thì cộng thêm 44 tiếng, cho ra A3.
  • Rồi lại quay vòng tiếp, nếu A3 rơi vào khoảng nghỉ trưa thì lại cộng thêm 2 tiếng
  • V.v...
  • Cho tới khi nào cái kết quả này nằm trong khoảng thời gian chấp nhận được (rơi vào trong giờ hành chánh) thì dừng lại.
(Các điều kiện kiểm tra trên có thể còn thiếu... em chỉ ví dụ thôi)

Liệu có khả thi không ạ ?
 
Quả đúng là Cực Khó!
Em nghĩ rằng chắc không dùng công thức nổi, giả như có nổi đi nữa thì chắc cái công thức này sẽ dài khủng khiếp, và phải rất nhiều công thức thì mới có thể chơi nổi!
Em có ý tưởng này, dùng VBA. Nhưng em thì không giỏi về VBA, nên xin nêu ra ý tưởng thôi, các bác xem có khả thi không thì làm dùm...

Lấy thời gian bắt đầu + thời gian dự định sẽ hoàn thành công việc, ra kết quả là A chẳng hạn. Rồi dùng vòng lặp để kiểm tra kết quả A:
  • Nếu A rơi vào khoảng nghỉ trưa (tử 11:30 đến 13:30) thì cộng thêm 2 tiếng. Cho ra A1.
  • Nếu A1 rơi vào khoảng nghỉ chiều (từ 17:00 đến 7:30 ngày hôm sau) thì cộng thêm 14,5 tiếng. Cho ra A2.
  • Nếu A2 rơi vào trưa thứ 7 (sau 11:30) thì cộng thêm 44 tiếng, cho ra A3.
  • Rồi lại quay vòng tiếp, nếu A3 rơi vào khoảng nghỉ trưa thì lại cộng thêm 2 tiếng
  • V.v...
  • Cho tới khi nào cái kết quả này nằm trong khoảng thời gian chấp nhận được (rơi vào trong giờ hành chánh) thì dừng lại.
(Các điều kiện kiểm tra trên có thể còn thiếu... em chỉ ví dụ thôi)

Liệu có khả thi không ạ ?
Tôi thì nghĩ vầy:
- Lấy thời gian bắt đầu + TG dự kiến + với 1 số gia nào đó (số gia này dựa vào khoãng nghĩ nào mà ta cho là lớn nhất, theo tôi đó là ngày CN) ---> Ra được 1 tổng mới, đăt nó là M chẳng hạn
- Dùng For quét i từ 1 đến M
- Xét Start + i xem chúng có lọt vào các khoảng nghĩ không? Nếu không lọt thi "nhớ" số i này vào 1 biến, chẳng hạn là K (nếu lọt vào khoảng nghĩ thì ta vẩn + i nhưng không "nhớ")
- Cứ thế tiếp diển ---> Đến khi nào tổng số "nhớ" K đúng bằng với TG dự kiến thì OK "con gà đen" ---> Thoát ---> Finish = Start + i
Đại khái là vậy ---> Nhưng vẫn "tê" (vì GIỜ GIẤC xem bộ khó ăn hơn NGÀY THÁNG) ---> Và sẽ còn khó khăn hơn nếu phải xét đến các ngày LỂ
 
Tôi gởi file nhờ các bạn xem giúp tối ưu hóa , mới tập viết code ,nhưng thấy nhiều IF quá , và chưa phát hiện sai .
Tôi đã làm tìm thời gian thực tế (Chưa biết ổn không), còn thời gian dự định chưa làm được , mời các bạn động não tiếp . Cảm ơn
 

File đính kèm

Tôi gởi file nhờ các bạn xem giúp tối ưu hóa , mới tập viết code ,nhưng thấy nhiều IF quá , và chưa phát hiện sai .
Tôi đã làm tìm thời gian thực tế (Chưa biết ổn không), còn thời gian dự định chưa làm được , mời các bạn động não tiếp . Cảm ơn
Em làm thử 1 function EstEndDate dự kiến ngày kết thúc. Anh xem thử có OK, em làm tiếp phần kia.
Cú pháp EstEndTime(Ngaydau, số giờ)
PHP:
Function EstEndTime(NgayDau As Variant, SoPhut As Long)
Dim NgayCuoi As Variant, iPhut As Long, IntervalType As String
IntervalType = "n"
SoPhut = SoPhut * 60
If Weekday(NgayDau) = 1 Then Exit Function 'xem lai cac dieu kien ve t7, CN
If Not IsDate(NgayDau) Then Exit Function
If SoPhut = 0 Then
    EstEndTime = NgayCuoi
    Exit Function
End If
iPhut = 30
Do While Not iPhut = SoPhut + 30
    NgayCuoi = DateAdd(IntervalType, 30, NgayDau)
        If Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 And iPhut < SoPhut Then
            NgayDau = DateAdd(IntervalType, 120, NgayCuoi)
        ElseIf Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 17 And Minute(NgayCuoi) = 0 And iPhut < SoPhut Then
             NgayDau = DateAdd(IntervalType, 14 * 60 + 30, NgayCuoi)
        ElseIf Weekday(NgayDau) = 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 And iPhut < SoPhut Then
             NgayDau = DateAdd(IntervalType, 44 * 60, NgayCuoi)
        Else
            NgayDau = NgayCuoi
        End If
        iPhut = iPhut + 30
Loop
EstEndTime = NgayCuoi
End Function
 
Hình như là số giờ chứ không phải số phút
Và chỉ OK đối với số giờ chẵn .
 
Hình như là số giờ chứ không phải số phút
Và chỉ OK đối với số giờ chẵn .
Chạy sub sau thì OK mà chưa hiểu sao chuyển sang UDF thì sai ở giờ end la 11h30
PHP:
Sub EndTime()
Dim NgayDau, NgayCuoi, iPhut As Long
With Application
    .Calculation = xlCalculationManual
End With
Dim SoPhut As Long
Dim IntervalType As String
Sheet2.Select
IntervalType = "n"
NgayDau = Cells(2, 2)
SoPhut = Cells(1, 2) * 60
If Weekday(NgayDau) = 1 Then Exit Sub 'xem lai thu sau
iPhut = 30
Do While Not iPhut = SoPhut + 30
    NgayCuoi = DateAdd(IntervalType, 30, NgayDau)
        If Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 And iPhut < SoPhut Then
            NgayDau = DateAdd(IntervalType, 120, NgayCuoi)
        ElseIf Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 17 And Minute(NgayCuoi) = 0 And iPhut < SoPhut Then
             NgayDau = DateAdd(IntervalType, 14 * 60 + 30, NgayCuoi)
        ElseIf Weekday(NgayDau) = 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 And iPhut < SoPhut Then
             NgayDau = DateAdd(IntervalType, 44 * 60, NgayCuoi)
        Else
            NgayDau = NgayCuoi
        End If
        iPhut = iPhut + 30
Loop
Cells(2, 3) = NgayCuoi
End Sub
Anh chạy thử sub sau.
 
Chưa ổn lắm nhưng không hiểu ý nghĩa mấy chữ trong câu này nên cũng chưa biết nên sửa thế nào : NgayDau = DateAdd(IntervalType, 120, NgayCuoi)
Mình nói rõ thêm là Giờ định mức ấy có thể là : 10 ph ,15 ph , ... 30 ph,35 ph...1 g ,..
 
Chưa ổn lắm nhưng không hiểu ý nghĩa mấy chữ trong câu này nên cũng chưa biết nên sửa thế nào : NgayDau = DateAdd(IntervalType, 120, NgayCuoi)
Mình nói rõ thêm là Giờ định mức ấy có thể là : 10 ph ,15 ph , ... 30 ph,35 ph...1 g ,..
Bạn nghiên cứu hàm DateAdd nó cũng tựa như hàm Datedif.
Em chưa hiểu Định mức công việc(g) này là nhập theo dạng gì, trước mắt làm theo số. Cụ thể 1.5 là 1h30, 1.1 là 1h6'
Bác thử lại UDF này xem sao, do code chiều sai ở khai biến.
Em cho 1 block là 30', Bác có thể sửa lại thành 5, 10...
PHP:
Function EndTime(NgayDau As Variant, SoPhut As Double)
Dim NgayCuoi As Variant, iPhut As Double, Block As Long
SoPhut = SoPhut * 60 'xem lai neu 1h5' thi nhap so the nao'
If Weekday(NgayDau) = 1 Then Exit Function 'xem lai cac dieu kien ve t7, CN'
If Not IsDate(NgayDau) Then Exit Function
Block = 30
If SoPhut = 0 Then
    EndTime = NgayCuoi
    Exit Function
End If
iPhut = Block
Do While Not iPhut = SoPhut + Block
    NgayCuoi = DateAdd("n", Block, NgayDau)
        If Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 Then
            NgayDau = DateAdd("n", 120, NgayCuoi)
        ElseIf Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 17 And Minute(NgayCuoi) = 0 Then
             NgayDau = DateAdd("n", 14 * 60 + 30, NgayCuoi)
        ElseIf Weekday(NgayDau) = 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 Then
             NgayDau = DateAdd("n", 44 * 60, NgayCuoi)
        Else
            NgayDau = NgayCuoi
        End If
        iPhut = iPhut + Block
Loop
EndTime = NgayCuoi
End Function
Nếu Block là 5,10,15, 30, 45,60' thì dễ hơn, còn block 12' thì chưa biết cách làm. Nên nhập vào thời gian dm là số phút thay vì 1.1, 1.2...Khó chia mà phải làm tròn. Hay là Bác đưa tình huống khác.
 

File đính kèm

Lần chỉnh sửa cuối:
Mình nói rõ thêm là Giờ định mức ấy có thể là : 10 ph ,15 ph , ... 30 ph,35 ph...1 g ,..
Em mày mò gần xong rồi, nhưng chỉ tính giờ định mức là bội số của 30 phút thôi... theo cái ví dụ ban đầu của bác. Giờ nghe bác nói vầy... oải quá!
 
Xin lỗi do nói chưa rõ ràng , nhưng các bạn đã làm bội số 30 được thì bội số cho 1 hoặc 5 chắc là không khó . Còn định dạng thì mình có thể đổi qua lại được mà .
 
PHP:
Xin lỗi do nói chưa rõ ràng , nhưng các bạn đã làm bội số 30 được thì bội số cho 1 hoặc 5 chắc là không khó . Còn định dạng thì mình có thể đổi qua lại được mà .
Bác cụ thể cho em một ví dụ. Và quan trọng là Định mức công việc(g) Bác nhập theo dạng gì. 1.5h hay là 1:30' hay 1.2h hay là 1:12'. Bác sửa trong UDF của em thay block =1 xem thử nhưng mà sẽ chậm vì step 1'
Bác sử dụng code sau thử.
PHP:
Function EndTime(NgayDau As Variant, SoPhut As Double)
Dim NgayCuoi As Variant, iPhut As Double, Block As Long
On Error Resume Next
SoPhut = Round(SoPhut * 60, 0) 'xem lai neu 1h5' thi nhap so the nao'
If Weekday(NgayDau) = 1 Then Exit Function 'xem lai cac dieu kien ve t7, CN'
If Not IsDate(NgayDau) Then Exit Function
Block = 1
If SoPhut = 0 Then
    EndTime = NgayCuoi
    Exit Function
End If
iPhut = Block
Do While Not iPhut = SoPhut + Block
    NgayCuoi = DateAdd("n", Block, NgayDau)
        If Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 Then
            NgayDau = DateAdd("n", 120, NgayCuoi)
        ElseIf Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 17 And Minute(NgayCuoi) = 0 Then
             NgayDau = DateAdd("n", 14 * 60 + 30, NgayCuoi)
        ElseIf Weekday(NgayDau) = 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 Then
             NgayDau = DateAdd("n", 44 * 60, NgayCuoi)
        Else
            NgayDau = NgayCuoi
        End If
        iPhut = iPhut + Block
Loop
EndTime = NgayCuoi
End Function
 
Lần chỉnh sửa cuối:
Cho em góp vui 1 đoạn code, ko rõ có đúng không mong các bác kiểm tra lại giúp. Trong code em chưa kiểm tra trường hợp người dùng nhập vào giá trị không hợp lệ :)
Mã:
Function GetEndTime(BatDau, ThoiGian)
    Dim SoTuan, SoNgay, ret, ThoiGianCon
    
    Dim ThoiGianTemp
    ThoiGianTemp = TimeSerial(Hour(BatDau), Minute(BatDau), 0)
    If ThoiGianTemp > TimeSerial(13, 30, 0) Then
        ThoiGianTemp = TimeSerial(4, 0, 0) + TimeSerial(13, 30, 0) - ThoiGianTemp
    Else
        ThoiGianTemp = ThoiGianTemp - TimeSerial(7, 30, 0)
    End If
    ThoiGian = ThoiGian + Hour(ThoiGianTemp) + Minute(ThoiGianTemp) / 60
    
    BatDau = DateSerial(Year(BatDau), Month(BatDau), Day(BatDau)) + TimeSerial(7, 30, 0)
    
    SoTuan = ThoiGian \ 41.5
    ThoiGianCon = ThoiGian - SoTuan * 41.5
    ret = BatDau + SoTuan * 7
    Do While (Weekday(ret) <> 7 And ThoiGianCon >= 7.5) Or (Weekday(ret) = 7 And ThoiGianCon >= 4)
        ThoiGianCon = ThoiGianCon - 4
        If Weekday(ret) < 7 Then ThoiGianCon = ThoiGianCon - 3.5
        If ThoiGianCon = 0 Then Exit Do
        ret = ret + 1
        If Weekday(ret) = 1 Then ret = ret + 1
    Loop
    If ThoiGianCon = 0 Then
        ret = ret + TimeSerial(4, 0, 0)
        If Weekday(ret) <> 7 Then ret = ret + TimeSerial(5, 30, 0)
    ElseIf ThoiGianCon > 4 Then
        ThoiGianCon = ThoiGianCon - 4
        ret = ret + TimeSerial(Int(ThoiGianCon), (ThoiGianCon - Int(ThoiGianCon)) * 60, 0) + TimeSerial(6, 0, 0)
    Else
        ret = ret + TimeSerial(Int(ThoiGianCon), (ThoiGianCon - Int(ThoiGianCon)) * 60, 0)
    End If
    GetEndTime = ret
End Function
 

File đính kèm

Xin gửi lên bài giải của em. Hoàn toàn bằng công thức.
Nhưng đơn vị thời gian nhỏ nhất là mỗi 30 phút. Em không thể làm với thời gian nhỏ hơn...
Nhờ các bác kiểm tra dùm xem có sai ở đâu nữa không.
 

File đính kèm

Cho em góp vui 1 đoạn code, ko rõ có đúng không mong các bác kiểm tra lại giúp. Trong code em chưa kiểm tra trường hợp người dùng nhập vào giá trị không hợp lệ :)
Bạn rollover79 xem thử nha:
Công thức của bạn bị sai khi số thời gian định mức = 41.5
Ví dụ:
  • Ngày 05/1/2009, bắt đầu lúc 7 giờ 30, định mức 41 tiếng -- Kết quả: 11 giờ ngày 10/1/2009 (đúng)
  • Tăng định mức thêm nửa tiếng, nghĩa là kết quả cũng phải tăng nửa tiếng (11 giờ 30 ngày 10/1/2009), nhưng UDF của bạn ra 17 giờ ngày 12/1/2009 !
  • Tăng thêm nửa tiếng nửa, kết quả là 8 giờ ngày 12/1/2009: Đúng!

-----------------------------
Em tính test luôn cái của anh Thu Nghi, nhưng nó chạy chậm quá anh ơi, không kiên nhẫn nổi...
 
Lần chỉnh sửa cuối:
Cảm ơn bác BNTT, test nhiều trường hợp mà quên mất trường hợp làm chẵn tuần và thời gian bắt đầu là 7h:30. Xin sửa lại code như sau các bác test tiếp xem còn lỗi nào không nhé.
Với cách của bác ThuNghi mà khi dữ liệu lớn hoặc nhiều thì không ổn về mặt tốc độ, vì bác dùng vòng For với step là 1 phút nên tốc độ sẽ bị phụ thuộc nhiều vào thời gian.
Còn đây là thuật toán của em, hơi dài nên xin được tóm tắt thế này mong các bác góp ý thêm.
- Đưa thời gian bắt đầu về 7:30(bắt đầu 1 ngày) bằng cách cộng thêm vào thời gian định mức 1 khoảng hợp lý. Ví dụ đang bắt đầu từ 8:30 ngày 5/1/2009 và định mức là 5 thì thay bằng bắt đầu từ 7:30 ngày 5/1/2009 và định mức là 5.5
- Từ bảng thời gian làm việc ban đầu ta thấy mỗi tuần làm 41.5 tiếng, vậy với định mức ban đầu ta tính xem phải làm bao nhiêu tuần, cộng luôn số ngày trong các tuần này vào ngày ban đầu, phần thời gian còn lại(còn lại chắc chắn chưa đến 1 tuần<41.5). Duyệt lần lượt các ngày tiếp theo, ngày thường thì thời gian còn lại trừ đi 7.5 là thời gian làm việc ngày thường, tương tự nếu là ngày thứ 7 thì trừ đi 4, chủ nhật thì trừ đi 0, đến khi nào thời gian còn lại không đủ cho 1 ngày làm việc thì đem thời gian đó cộng với ngày cuối cùng tìm được.
- Với giải thuật này có thể thực hiện hoàn toàn bằng công thức được, nhưng vẫn hơi phức tạp và sẽ phải tạo thêm cột phụ. Và với VBA thì số vòng lặp cũng không vượt quá 7 nên tốc độ sẽ hầu như không phụ thuộc vào thời gian định mức.
Mã:
Function GetEndTime(BatDau, ThoiGian)
    Dim SoTuan, SoNgay, ret, ThoiGianCon
    
    Dim ThoiGianTemp
    ThoiGianTemp = TimeSerial(Hour(BatDau), Minute(BatDau), 0)
    If ThoiGianTemp > TimeSerial(13, 30, 0) Then
        ThoiGianTemp = TimeSerial(4, 0, 0) + TimeSerial(13, 30, 0) - ThoiGianTemp
    Else
        ThoiGianTemp = ThoiGianTemp - TimeSerial(7, 30, 0)
    End If
    ThoiGian = ThoiGian + Hour(ThoiGianTemp) + Minute(ThoiGianTemp) / 60
    
    BatDau = DateSerial(Year(BatDau), Month(BatDau), Day(BatDau)) + TimeSerial(7, 30, 0)
    
    SoTuan = ThoiGian \ 41.5
    ThoiGianCon = ThoiGian - SoTuan * 41.5
    ret = BatDau + SoTuan * 7
    If ThoiGianCon > 0 Then
        Do While (Weekday(ret) <> 7 And ThoiGianCon >= 7.5) Or (Weekday(ret) = 7 And ThoiGianCon >= 4)
            ThoiGianCon = ThoiGianCon - 4
            If Weekday(ret) < 7 Then ThoiGianCon = ThoiGianCon - 3.5
            If ThoiGianCon = 0 Then Exit Do
            ret = ret + 1
            If Weekday(ret) = 1 Then ret = ret + 1
        Loop
        If ThoiGianCon = 0 Then
            ret = ret + TimeSerial(4, 0, 0)
            If Weekday(ret) <> 7 Then ret = ret + TimeSerial(5, 30, 0)
        ElseIf ThoiGianCon > 4 Then
            ThoiGianCon = ThoiGianCon - 4
            ret = ret + TimeSerial(Int(ThoiGianCon), (ThoiGianCon - Int(ThoiGianCon)) * 60, 0) + TimeSerial(6, 0, 0)
        Else
            ret = ret + TimeSerial(Int(ThoiGianCon), (ThoiGianCon - Int(ThoiGianCon)) * 60, 0)
        End If
    End If
    
    If True And TimeSerial(7, 30, 0) = TimeSerial(Hour(ret), Minute(ret), Second(ret)) Then
        ret = (ret - 1) + TimeSerial(9, 30, 0)
        If Weekday(ret) = 1 Then ret = (ret - 1) - TimeSerial(5, 30, 0)
    End If
    GetEndTime = ret
End Function
 

File đính kèm

Nhờ Bác RollOver79 làm hộ code ngược lại
Ta có ngày giờ đầu, cuối => số phút (h).
Tôi dùng code trên làm ngược lại vòng do sao cho có ngày giờ đầu = cuối => => số phút (h) mà chưa được
Cụ thể như
Function TimGio(NgayDau, NgayCuoi)
Do while endTime(NgayDau,SoGio) = NgayCuoi
...
Loop
end Function
Cám ơn Bạn nhiều. Đang học Do ...Loop mà chưa hiểu nhiểu.
 
Sau một đêm ngủ không được, tôi đã tìm được cách để đưa đơn vị thời gian định mức về mỗi 5 phút. Xin gửi lên bản "version 1.4", đã được hiệu chỉnh. Bảng tính này cũng hoàn toàn dùng công thức và các Name, không dùng cột phụ.

Khi nhập liệu, phải nhập cho đúng quy cách: Thời gian định mức (ô F3) là mỗi 5 phút, và phải chia cho 60, thời gian bắt đầu (ô F4) thì phải đúng dạng dd/mm/yyyy hh:mm, nhập sai nó tính sai ráng chịu! Chính vì cái phiền toái này mà tôi chế thêm cách dùng chuột để điều khiển các Control, đỡ mất công tính nhẩm, nhớ định dạng, mà lại dễ dàng để test các kết quả. Hiện tại các Control này bị giới hạn mức Maximum và Minimum, nếu cảm thấy như vậy là chưa đủ, các bạn chỉ việc thay đổi Properties của nó.
000-166.png

Cũng gần gần giống bạn rollover79, tất cả các ngày trong tuần, tôi đều đưa về thứ Hai, bằng cách bù trừ một khoảng thời gian hợp lý.
Dựa vào khoảng thời gian định mức đã biết, trước hết tôi tìm ra số tuần lễ sẽ trôi qua, bằng cách chia cho 41.5 (thời gian làm việc của một tuần).
Sau đó tính tiếp số giờ nghỉ buổi trưa (2 tiếng) nếu có.
Rồi tìm tiếp thời gian nghỉ qua đêm (16.5 tiếng) nếu có.
Bởi đã giới hạn thời gian chỉ trong khoảng 41.5 tiếng, nên tôi không cần phải xét đến ngày thứ Bảy. Hễ mốc thời gian chạm mức 41.5 thì nó sẽ nhảy sang thứ Hai kế tiếp.
Sau cùng, tôi lấy thời gian bắt đầu, cộng thêm định mức, cộng thêm các khoảng nghỉ trưa, nghỉ qua đêm, và cộng thêm khoảng thời gian nghỉ (126.5 tiếng) nếu như định mức lớn hơn 1 tuần... Đó chính là kết quả cuối cùng.

Hy vọng bảng tính này sẽ đáp ứng được yêu cầu của bác Letin.

Giải thuật dùng trong bảng tính này, nếu so với các UserDefineName thì không đáng, bởi nó dài dòng... Tuy nhiên, nói cho vui, các bác có thể dùng nó để test các UDF... Hôm qua, tôi đã dùng bảng tính này để test code của bạn rollover79, nhờ đó mới khám phá cái lỗi đã nói cho bạn ở trên.

Lỗi nhảy sớm khi chạm mức 41.5 này, tôi cũng đã mắc phải. Cách xử lý của tôi hơi củ chuối tí... Tôi cộng thêm một khoảng thời gian tối thiểu (ở đây là 5 phút) vào tổng thời gian trước khi đem chia cho 41.5, như thế, nếu như thời gian định mức bằng đúng 41.5, kết quả sẽ không bị nhảy sớm. Tôi chỉ tính nhẩm thôi, ví dụ bắt đầu làm lúc 7:30 ngày thứ Hai, với định mức bằng 41.5 tiếng, bằng đúng thời gian làm của 1 tuần, thì kết quả phải là lúc 11:30 ngày thứ Bảy... (chưa đủ để nhảy sang 1 tuần mới, mặc dù 41.5/41.5 là 1)
 

File đính kèm

Lần chỉnh sửa cuối:
Nhờ Bác RollOver79 làm hộ code ngược lại
Ta có ngày giờ đầu, cuối => số phút (h).
Tôi dùng code trên làm ngược lại vòng do sao cho có ngày giờ đầu = cuối => => số phút (h) mà chưa được
Cụ thể như
Function TimGio(NgayDau, NgayCuoi)
Do while endTime(NgayDau,SoGio) = NgayCuoi
...
Loop
end Function
Cám ơn Bạn nhiều. Đang học Do ...Loop mà chưa hiểu nhiểu.
Với bài toán ngược này thì dễ hơn bài toàn xuôi nhiều, cách đơn giản là bác lặp hết các ngày cũng ra. Nhưng bác có thể giảm bớt số vòng lặp bằng cách tính trọn thời gian trong ngày và trong tuần. Mỗi tuần là 41.5, mỗi ngày thường là 7.5, thứ 7 là 4. Sau khi ra kết quả thì bác trừ đi 2 khoảng đầu ngày bắt đầu và khoảng cuối của ngày kết thúc là xong.
Mã:
Function GetTime(BatDau, KetThuc)
    Dim NgayDau, NgayCuoi, SoTuan, ret, i
    NgayDau = DateSerial(Year(BatDau), Month(BatDau), Day(BatDau))
    NgayCuoi = DateSerial(Year(KetThuc), Month(KetThuc), Day(KetThuc))
    SoTuan = DateDiff("d", NgayDau, NgayCuoi) \ 7
    ret = SoTuan * 41.5
    NgayDau = NgayDau + SoTuan * 7
    For i = NgayDau To NgayCuoi
        Select Case Weekday(i)
            Case 7: ret = ret + 4
            Case 2, 3, 4, 5, 6: ret = ret + 7.5
        End Select
    Next
    Dim ThoiGianTemp
    ThoiGianTemp = TimeSerial(Hour(BatDau), Minute(BatDau), 0)
    If ThoiGianTemp > TimeSerial(13, 30, 0) Then
        ThoiGianTemp = TimeSerial(4, 0, 0) + TimeSerial(13, 30, 0) - ThoiGianTemp
    Else
        ThoiGianTemp = ThoiGianTemp - TimeSerial(7, 30, 0)
    End If
    
    ret = ret - Hour(ThoiGianTemp) - Minute(ThoiGianTemp) / 60
    
    ThoiGianTemp = TimeSerial(Hour(KetThuc), Minute(KetThuc), 0)
    If ThoiGianTemp > TimeSerial(13, 30, 0) Then
        ThoiGianTemp = TimeSerial(17, 0, 0) - ThoiGianTemp
    Else
        ThoiGianTemp = TimeSerial(11, 30, 0) - ThoiGianTemp
        If Weekday(KetThuc) <> 7 Then ThoiGianTemp = ThoiGianTemp + TimeSerial(3, 30, 0)
    End If
    
    ret = ret - Hour(ThoiGianTemp) - Minute(ThoiGianTemp) / 60
    
    GetTime = ret
End Function
 
Bác Letin có thể cho nhận xét cái bảng tính của em được không ạ ?
Về tốc độ, về sự chính xác ?
 
Tôi xin điều chỉnh lại code, do chưa kiểm tra giờ ngày đầu có phải là 11h30 hay 17h
PHP:
Option Explicit
Public Function EndTime(NgayDau As Variant, SoGio As Double)
Dim NgayCuoi As Variant, iPhut As Double, Block As Long, SoPhut As Long
On Error Resume Next
Application.Volatile
SoPhut = Round(SoGio * 60, 0) 'xem lai neu 1h5' thi nhap so the nao'
If Not IsDate(NgayDau) Then Exit Function
'Xac dinh gio ngay dau co phai la 11h30 hay 17h hay 11h30 TB'
Select Case Weekday(NgayDau)
  Case Weekday(NgayDau) = 1 'neu la CN'
    Exit Function
  Case Is <> 7 'Neu khac thu 7'
    If Hour(NgayDau) = 11 And Minute(NgayDau) = 30 Then
      NgayDau = DateAdd("n", 120, NgayDau)
    ElseIf Hour(NgayDau) = 17 And Minute(NgayDau) = 0 Then
     NgayDau = DateAdd("n", 14 * 60 + 30, NgayDau)
    End If
  Case Is = 7 'neu la th 7'
    If Hour(NgayDau) = 11 And Minute(NgayDau) = 30 Then
      NgayDau = DateAdd("n", 44 * 60, NgayDau)
    End If
End Select
If SoPhut = 0 Then
  EndTime = NgayCuoi
  Exit Function
End If
Block = 1
iPhut = Block
Do While Not iPhut = SoPhut + Block
  NgayCuoi = DateAdd("n", Block, NgayDau)
  If Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 Then
    NgayDau = DateAdd("n", 120, NgayCuoi)
  ElseIf Weekday(NgayDau) <> 7 And Hour(NgayCuoi) = 17 And Minute(NgayCuoi) = 0 Then
     NgayDau = DateAdd("n", 14 * 60 + 30, NgayCuoi)
  ElseIf Weekday(NgayDau) = 7 And Hour(NgayCuoi) = 11 And Minute(NgayCuoi) = 30 Then
     NgayDau = DateAdd("n", 44 * 60, NgayCuoi)
  Else
    NgayDau = NgayCuoi
  End If
  iPhut = iPhut + Block
Loop
EndTime = NgayCuoi
End Function
To RollOver79
Hình như UDF GetEndTim chưa chuẩn với ngaydau là
12/01/2009 3:00:00 PM và sogio là 1.
Đáp số phải là 12/01/2009 4:00:00 PM
 
Cảm ơn bác BNTT, test nhiều trường hợp mà quên mất trường hợp làm chẵn tuần và thời gian bắt đầu là 7h:30. Xin sửa lại code như sau các bác test tiếp xem còn lỗi nào không nhé.
Với cách của bác ThuNghi mà khi dữ liệu lớn hoặc nhiều thì không ổn về mặt tốc độ, vì bác dùng vòng For với step là 1 phút nên tốc độ sẽ bị phụ thuộc nhiều vào thời gian.
Còn đây là thuật toán của em, hơi dài nên xin được tóm tắt thế này mong các bác góp ý thêm.
- Đưa thời gian bắt đầu về 7:30(bắt đầu 1 ngày) bằng cách cộng thêm vào thời gian định mức 1 khoảng hợp lý. Ví dụ đang bắt đầu từ 8:30 ngày 5/1/2009 và định mức là 5 thì thay bằng bắt đầu từ 7:30 ngày 5/1/2009 và định mức là 5.5
- Từ bảng thời gian làm việc ban đầu ta thấy mỗi tuần làm 41.5 tiếng, vậy với định mức ban đầu ta tính xem phải làm bao nhiêu tuần, cộng luôn số ngày trong các tuần này vào ngày ban đầu, phần thời gian còn lại(còn lại chắc chắn chưa đến 1 tuần<41.5). Duyệt lần lượt các ngày tiếp theo, ngày thường thì thời gian còn lại trừ đi 7.5 là thời gian làm việc ngày thường, tương tự nếu là ngày thứ 7 thì trừ đi 4, chủ nhật thì trừ đi 0, đến khi nào thời gian còn lại không đủ cho 1 ngày làm việc thì đem thời gian đó cộng với ngày cuối cùng tìm được.
- Với giải thuật này có thể thực hiện hoàn toàn bằng công thức được, nhưng vẫn hơi phức tạp và sẽ phải tạo thêm cột phụ. Và với VBA thì số vòng lặp cũng không vượt quá 7 nên tốc độ sẽ hầu như không phụ thuộc vào thời gian định mức.

rollover79 thân, code của bạn, nếu thời gian bắt đầu là 13:30 trở đi thì chạy không đúng nữa. Tất cả các ngày, không riêng gì thứ 2.
 
Cảm ơn 2 bác ThuNghi và BNTT, trong code có 1 dòng bị sai logic
Mã:
Function GetEndTime(BatDau, ThoiGian)
    Dim SoTuan, SoNgay, ret, ThoiGianCon
    
    Dim ThoiGianTemp
    ThoiGianTemp = TimeSerial(Hour(BatDau), Minute(BatDau), 0)
    If ThoiGianTemp > TimeSerial(13, 30, 0) Then
        ThoiGianTemp = TimeSerial(4, 0, 0) + [COLOR=Red][B]TimeSerial(13, 30, 0) - ThoiGianTemp[/B][/COLOR]
    Else
        ThoiGianTemp = ThoiGianTemp - TimeSerial(7, 30, 0)
    End If
    ThoiGian = ThoiGian + Hour(ThoiGianTemp) + Minute(ThoiGianTemp) / 60
    
    BatDau = DateSerial(Year(BatDau), Month(BatDau), Day(BatDau)) + TimeSerial(7, 30, 0)
    
    SoTuan = ThoiGian \ 41.5
    ThoiGianCon = ThoiGian - SoTuan * 41.5
    ret = BatDau + SoTuan * 7
    If ThoiGianCon > 0 Then
        Do While (Weekday(ret) <> 7 And ThoiGianCon >= 7.5) Or (Weekday(ret) = 7 And ThoiGianCon >= 4)
            ThoiGianCon = ThoiGianCon - 4
            If Weekday(ret) < 7 Then ThoiGianCon = ThoiGianCon - 3.5
            If ThoiGianCon = 0 Then Exit Do
            ret = ret + 1
            If Weekday(ret) = 1 Then ret = ret + 1
        Loop
        If ThoiGianCon = 0 Then
            ret = ret + TimeSerial(4, 0, 0)
            If Weekday(ret) <> 7 Then ret = ret + TimeSerial(5, 30, 0)
        ElseIf ThoiGianCon > 4 Then
            ThoiGianCon = ThoiGianCon - 4
            ret = ret + TimeSerial(Int(ThoiGianCon), (ThoiGianCon - Int(ThoiGianCon)) * 60, 0) + TimeSerial(6, 0, 0)
        Else
            ret = ret + TimeSerial(Int(ThoiGianCon), (ThoiGianCon - Int(ThoiGianCon)) * 60, 0)
        End If
    End If
    
    If True And TimeSerial(7, 30, 0) = TimeSerial(Hour(ret), Minute(ret), Second(ret)) Then
        ret = (ret - 1) + TimeSerial(9, 30, 0)
        If Weekday(ret) = 1 Then ret = (ret - 1) - TimeSerial(5, 30, 0)
    End If
    GetEndTime = ret
End Function
Các bác thay lại giúp em chỗ bôi đỏ thành ThoiGianTemp - TimeSerial(13, 30, 0)
 
Version 2.0 đây.
Chính xác tới từng phút luôn.
Nếu dùng Control để nhập dữ liệu, có thêm tùy chọn cho bước nhảy của đơn vị thời gian định mức nhỏ nhất: Có thể chọn nhảy từng 1 phút, 5 phút, hay 30 phút mỗi lần.
000-168.jpg

--------------------------------------------------------
Em nói thêm một chút. Giải bài này, em mất hết 5 ngày (từ hôm mồng 9). Làm gì cũng nghĩ đến nó, cả khi ngủ, cho đến đêm hôm qua. Khi test lần cuối, thấy nó chạy quá ngọt, mừng ơi là mừng. Cảm ơn bác Letin đã cho một đề bài thật hay, và cảm ơn anh ndu96081631 nữa, anh chính là động lực để em quyết làm cho bằng được:
Bài toán dạng này không phải là KHÓ, mà là CỰC KHÓ
Cảm ơn cả sư nương nữa, đã bỏ công test lại dùm em và động viên em...
 

File đính kèm

Lần chỉnh sửa cuối:
Cảm ơn các bạn đã tham gia và động viên .
Thật là cảm động đối với bạn BNTT , rất kỳ công , tôi cũng đã tốn thời gian với việc này và tôi nghĩ các bạn ThuNghi , rollover79 cũng vậy ,bạn NDU đã châm ngòi và nhiều bạn khác động viên .
Kết quả của mỗi giải pháp các bạn đưa ra ,đối với tôi đều đáng học tập cả .
Rất nhiệt tình , tuy Khó nhưng không tay là điều thật đáng quí , đều được trân trọng .
Một lần nữa cảm ơn và chúc các bạn thành đạt .
 
Chậm chân một chút!
Có 1 thuật toán đơn giản, tôi nghĩ ra từ 3 ngày nay, nhưng chưa làm được. Bây giờ mới xong, nhờ các bạn kiểm tra hộ:

1. tính thời gian còn lại (A) của ngày bắt đầu: thí dụ bắt đầu 10:00, số giờ còn lại là 1,5 giờ cho ngày thứ bảy và 5 giờ cho ngày thường.

2. So sánh giờ định mức với A:
a. nếu nhỏ hơn thì tính ngay
b. Nếu lớn hơn:​
b.1- số ngày cộng thêm = 0, Dùng 1 vòng lặp Do:

b.2- cho số ngày cộng thêm tăng thêm 1
b.3- nếu ngày bắt đầu cộng với số ngày cộng thêm là chủ nhật, tăng số ngày cộng thêm lên 1 nữa
b.4- tính số giờ còn lại sau khi cộng thêm 1 ngày
b.4.1- Nếu số giờ còn lại đó lớn hơn 4 giờ (thứ bảy), hoặc 7,5 giờ (ngày thường), loop (quay lại b.2)
b.4.2- Nếu số giờ còn lại nhỏ hơn 4 giờ (thứ bảy), hoặc 7,5 giờ (ngày thường), thoát Do​
3. Ngày kết thúc = ngày bắt đầu (quy về 0:00 sáng) + số ngày cộng thêm

4. Giờ kết thúc = 7:30 + số giờ còn lại (ở cuối phần Do loop) + thêm 2 giờ nếu ngày thường và sau 11:30

Có thể tính chính xác đến 1 phút.

Nhờ mọi người kiểm tra hộ. Có 3 cái scrollbar để tiện cho việc kiểm tra: 1 cái tăng định mức thêm 1 giờ, 1 cái tăng thêm 5 phút, 1 cái tăng thêm 1 phút.
Xin cám ơn.
 

File đính kèm

Lần chỉnh sửa cuối:
Chậm chân một chút!
Có 1 thuật toán đơn giản, tôi nghĩ ra từ 3 ngày nay, nhưng chưa làm được. Bây giờ mới xong, nhờ các bạn kiểm tra hộ:

1. tính thời gian còn lại (A) của ngày bắt đầu: thí dụ bắt đầu 10:00, số giờ còn lại là 1,5 giờ cho ngày thứ bảy và 5 giờ cho ngày thường.

2. So sánh giờ định mức với A:
a. nếu nhỏ hơn thì tính ngay
b. Nếu lớn hơn:​
b.1- số ngày cộng thêm = 0, Dùng 1 vòng lặp Do:

b.2- cho số ngày cộng thêm tăng thêm 1
b.3- nếu ngày bắt đầu cộng với số ngày cộng thêm là chủ nhật, tăng số ngày ôộng thêm lên 1 nữa
b.4- tính số giờ còn lại sau khi cộng thêm 1 ngày
b.4.1- Nếu số giờ còn lại đó lớn hơn 4 giờ (thứ bảy), hoặc 7,5 giờ (ngày thường), loop (quay lại b.2)
b.4.2- Nếu số giờ còn lại nhỏ hơn 4 giờ (thứ bảy), hoặc 7,5 giờ (ngày thường), thoát Do​
3. Ngày kết thúc = ngày bắt đầu (quy về 7:30 sáng) + số ngày cộng thêm

4. Giờ kết thúc = 7:30 + số giờ còn lại (ở cuối phần Do loop) + thêm 2 giờ nếu ngày thường và sau 11:30

Có thể tính chính xác đến 1 phút.

Nhờ mọi người kiểm tra hộ. Có 3 cái scrollbar để tiện cho việc kiểm tra: 1 cái tăng định mức thêm 1 giờ, 1 cái tăng thêm 5 phút, 1 cái tăng thêm 1 phút.
Xin cám ơn.
Em mới thử trường hợp này thấy chưa đúng.
- Bắt đầu từ 15h ngày 12/01/2009, định mức là 1. Kết quả ra 8h30 ngày 13/01/2009(sai) đúng phải là 16h ngày 12/01/2009.
 
Cám ơn Rollover, đúng là chỗ mà mình phân vân, nghĩ rằng sẽ sai, mà không biết lý do vì sao mà phân vân. Bây giờ thì biết rồi, xin vui lòng tải lại file bài này.
 

File đính kèm

Lần chỉnh sửa cuối:
Cám ơn Rollover, đúng là chỗ mà mình phân vân, nghĩ rằng sẽ sai, mà không biết lý do. Bây giờ thì biết rồi, xin vui lòng tải lại file bài này.
Nếu này đầu là
12/01/2009 11:30:00 AM
Và thời gian cộng thêm là 1 phút thì đáp số phải là 12/01/2009 1:31:00 PM
Nhưng Bác ra là.
12/01/2009 11:32:00 AM
 
Nếu này đầu là
12/01/2009 11:30:00 AM
Và thời gian cộng thêm là 1 phút thì đáp số phải là 12/01/2009 1:31:00 PM
Nhưng Bác ra là.
12/01/2009 11:32:00 AM
Tính 1 phút thì có vẻ chi li quá, 1h thì kết quả vẫn bị sai vì cho ra kết quả là 12/01/2009 12:30, lẽ ra kết quả phải cho ra 12/01/2009 14:30.
- Cách này là bác lặp theo từng ngày, như vậy nhanh hơn cách của bác ThuNghi đáng kể, nhưng vẫn bị chậm khi số ngày quá lớn. Em thử lấy ví dụ để so sánh tốc độ với code của em 1 chút thôi nhé, không có ý nghĩa thực tế. Nếu định mức là 2.158.000(2158000=1000*52*41.5) tức là vào khoảng 1000 năm thì code của bác chạy sẽ tương đối lâu.
 
Thiếu 1 dấu bằng (=) chỗ dưới đây:
Mã:
If TThisDay >= WorkTime Then

BeginTime = Hour(BeginDate) + Minute(BeginDate) / 60
GetEndPoint = BeginDate + WorkTime / 24 + _
IIf(BeginTime <[COLOR="Red"][B]=[/B][/COLOR] 11.5 And BeginTime + WorkTime > 11.5, 2 / 24, 0)
Exit Function

Mình giả định rằng với dự án lớn (trên 1 tháng), người ta tính bằng ngày, không tính bằng giờ với phút.

Nếu thực sự cần, thì thêm 1 điều kiện trước Do:
Mã:
If RestTime >= 41.5 then AddDays = 7 * (RestTime \ 41.5)
RestTime = RestTime Mod 41.5

Hoặc gán thẳng cho AddDays: (trước Do)
Mã:
AddDays = 7 * (RestTime \ 41.5)
RestTime = RestTime Mod 41.5


Sau đó tăng AddDays dần từng ngày (tối đa 6 vòng)
 
Lần chỉnh sửa cuối:
Sau đây là file đã chỉnh sửa theo gợi ý của RollOver: tính thêm số tuần nguyên x 7 để giảm số lần lặp.

Thêm nữa, chỉ cần định dạng lại ô kết quả, muốn tính tới 1 giây thì chơi lun! khỏi sửa code!

Nhân tiện, xin cảnh báo với mọi người là Hàm Mod của VBA trả về số nguyên.
Thí dụ:

46.50667 Mod 41.5 = 5 chứ không phải 5.00667
46.55667 Mod 41.5 = 5 !!!!

Muốn ra 5.00667 phải làm dài hơn:
= 46.50667 - 41.5 * (46.50667 \ 41.5)

To BNTT: vẫn còn nhảy sớm ngày trong trường hợp ngày giờ kết thúc là 11:30 thứ bảy, sẽ nhảy qua 7:30 thứ hai, dù rằng giữa 2 thời điểm này không có phút làm việc nào.
Trong file có sử dụng cả function của RollOver và công thức của BNTT để kiểm tra chéo.
 

File đính kèm

Lần chỉnh sửa cuối:
To BNTT: vẫn còn nhảy sớm ngày trong trường hợp ngày giờ kết thúc là 11:30 thứ bảy, sẽ nhảy qua 7:30 thứ hai, dù rằng giữa 2 thời điểm này không có phút làm việc nào.
Làm gì có chuyện đó bác ơi! Nếu kết quả là 11:30 thứ Bảy thì nó vẫn là 11:30 thứ Bảy.
Chứng minh bằng vài hình nhé:
002-23.jpg


001-41.jpg


000-169.jpg
 
Ừ , thử trên file gốc của BNTT thì không bị, nhưng copy 2 module, và vài ô số vào, thì lại bị. Không tìm được nguyên nhân.
 
Em đã đọc hết bài này và có tải về xem ,có chỉnh lại thời gian theo yêu cầu riêng là bắt đầu 7'30-11'30 chiều từ 12'30-16'30 thứ bày từ 7'30-11'30 chiều từ 12'30-16'30 CN nghỉ (CTY em làm 48 giờ 1 tuần).
Làm mãi mà không ra kết quả như ý .Kính mong các anh chị giúp em hoàn thành file.
Kính nhờ MOD xóa bài này
http://www.giaiphapexcel.com/forum/showthread.php?43216-xác-định-mốc-thời-gian-hoàn-thành-công-việc
do e không biết đã có đề tài rồi.
Em xin cảm ơn.
 
Các anh chị đâu rồi.Giúp em sửa code lại theo lịch thời gian của Cty em là đựơc .Em không thạo lắm về VB nên không biết chỉnh ra sao nữa
Kính mong các anh chị bớt chút thời gian cho em .
Em có dùng lại file của thầy PTM và có vào nghiên cứu code nhưng làm không đựơc(trình độ có hạn)
Em xin gửi file của thầy PTM để các anh chị cùng các thầy cô giúp em .
Em xin cám ơn.
 

File đính kèm

Lần chỉnh sửa cuối:
Kính mong các thầy cô cùng các anh chị giúp em
 
Kính mong các thầy cô cùng các anh chị giúp em
Cũng phải từ từ chứ bạn, đừng hối!
Tôi biết bài của bạn rất hay nhưng cũng rất khó ---> Đang suy nghĩ xem hướng nào tốt nhất ---> Tuy nó giống với hàm WorkdayVN mà tôi đã từng viết nhưng lại có những khó khăn riêng (chưa khắc phục được)
Dù sao bạn cũng phải để người ta "thở" chứ ---> Khi nào "thở" xong sẽ tính tiếp (không dám hứa)
 
Em đã tìm ra giải pháp cho vấn đề rồi.Cách này có gì sai xót không .Liệu có còn cách nào hay hơn cách này không.Kính nhờ các Thầy cô và các anh chị xem giúp file .
 

File đính kèm

Em đã tìm ra giải pháp cho vấn đề rồi.Cách này có gì sai xót không .Liệu có còn cách nào hay hơn cách này không.Kính nhờ các Thầy cô và các anh chị xem giúp file .
Chưa coi code, (bận quá), nhưng test vài cái thấy 1 chỗ không đúng. Xem file.

Tôi cũng đang sửa file cũ nhưng cũng còn đang test dở dang, còn lỗi, chưa dám post
 

File đính kèm

Chưa coi code, (bận quá), nhưng test vài cái thấy 1 chỗ không đúng. Xem file.

Tôi cũng đang sửa file cũ nhưng cũng còn đang test dở dang, còn lỗi, chưa dám post
Cám ơn thầy .Em test thấy đúng mà thầy.Em tính thế này :
Một ngày chỉ làm 8 giờ (480 phút) .nếu em giao việc cho ai đó lúc 7'30 với định mức cho phép phải hoàn thành trong 8 tiếng 30 phút (510 phút) thì kết quả là phài kết thúc công việc lúc 8giờ ngày hôm sau ,còn nếu rơi vào thứ 7 thì sẽ là 8 giờ ngày thứ 2. Em tính nếu công việc cần 16 tiếng phải hoàn thành thì ngừơi đó phải làm 2 ngày .
 
Xem trong file ấy. Tôi test với 8 ngày (quy ra giờ và phút), nhưng kết quả là 28 ngày

Nếu test đúng với vài con số và kết luận đúng 100% được, thì cao thủ như ndu đâu có gọi là "cực kỳ khó".
 
Lần chỉnh sửa cuối:
Nhờ mọi người test hộ với mọi trường hợp. Tôi đã test và sửa tới sửa lui 2 ngày nhưng vẫn sợ sót trường hợp.
Mã:
[COLOR=#000000][COLOR=#007700]Function [/COLOR][COLOR=#0000bb]GetEndPoint[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]WorkTime[/COLOR][COLOR=#007700])
[/COLOR][COLOR=#0000bb]Dim EsDate [/COLOR][COLOR=#007700]As [/COLOR][COLOR=#0000bb]Long[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]EsTime [/COLOR][COLOR=#007700]As [/COLOR][COLOR=#0000bb]Single[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]As [/COLOR][COLOR=#0000bb]Single[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]TimeAtDate[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]AddDays[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]BeginTime
[/COLOR][COLOR=#007700]Const [/COLOR][COLOR=#0000bb]BeginMor [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]7.5[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]EndMor [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]11.5
[/COLOR][COLOR=#007700]Const [/COLOR][COLOR=#0000bb]BeginAft [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]12.5[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]EndAft [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]16.5
[/COLOR][COLOR=#007700]Const Break = [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]DayWTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]8[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]WeekWTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]48

BeginTime [/COLOR][COLOR=#007700]= ([/COLOR][COLOR=#0000bb]BeginDate [/COLOR][COLOR=#007700]- [/COLOR][COLOR=#0000bb]Int[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700])) * [/COLOR][COLOR=#0000bb]24
TimeAtDate [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginTime [/COLOR][COLOR=#007700]<= [/COLOR][COLOR=#0000bb]EndMor[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]EndAft [/COLOR][COLOR=#007700]- Break, [/COLOR][COLOR=#0000bb]EndAft[/COLOR][COLOR=#007700]) - [/COLOR][COLOR=#0000bb]BeginTime
[/COLOR][COLOR=#007700]If [/COLOR][COLOR=#0000bb]TimeAtDate [/COLOR][COLOR=#007700]>= [/COLOR][COLOR=#0000bb]WorkTime Then
    GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]BeginDate [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]WorkTime [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24 [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]_
    IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginTime [/COLOR][COLOR=#007700]<= [/COLOR][COLOR=#0000bb]EndMor [/COLOR][COLOR=#007700]And [/COLOR][COLOR=#0000bb]BeginTime [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]WorkTime [/COLOR][COLOR=#007700]> [/COLOR][COLOR=#0000bb]EndMor[/COLOR][COLOR=#007700], Break / [/COLOR][COLOR=#0000bb]24[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])
    Exit Function
Else
    [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]WorkTime [/COLOR][COLOR=#007700]- [/COLOR][COLOR=#0000bb]TimeAtDate
    AddDays [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]7 [/COLOR][COLOR=#007700]* ([/COLOR][COLOR=#0000bb]RestTime  WeekWTime[/COLOR][COLOR=#007700])
    [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]- [/COLOR][COLOR=#0000bb]WeekWTime [/COLOR][COLOR=#007700]* ([/COLOR][COLOR=#0000bb]RestTime  WeekWTime[/COLOR][COLOR=#007700])
    If [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]0 Then
        GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]Int[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700]) + [/COLOR][COLOR=#0000bb]EndAft [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24 [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]_
        AddDays [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]Weekday[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]AddDays[/COLOR][COLOR=#007700]) = [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])
        Exit Function
    Else
        Do
            [/COLOR][COLOR=#0000bb]AddDays [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]AddDays [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]1
            AddDays [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]AddDays [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]Weekday[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]AddDays[/COLOR][COLOR=#007700]) = [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])
            If [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]<= [/COLOR][COLOR=#0000bb]DayWTime Then [/COLOR][COLOR=#007700]Exit Do
            [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]- [/COLOR][COLOR=#0000bb]DayWTime
        Loop
    End [/COLOR][COLOR=#007700]If
[/COLOR][COLOR=#0000bb]End [/COLOR][COLOR=#007700]If
[/COLOR][COLOR=#0000bb]GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]Int[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700]) + [/COLOR][COLOR=#0000bb]AddDays [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]BeginMor [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24
[/COLOR][COLOR=#007700]If [/COLOR][COLOR=#0000bb]Weekday[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]GetEndPoint[/COLOR][COLOR=#007700]) = [/COLOR][COLOR=#0000bb]1 Then GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]GetEndPoint [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]1
GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]GetEndPoint [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24 [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]BeginMor [/COLOR][COLOR=#007700]> [/COLOR][COLOR=#0000bb]EndMor[/COLOR][COLOR=#007700], Break / [/COLOR][COLOR=#0000bb]24[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])
[/COLOR][COLOR=#0000bb]End [/COLOR][COLOR=#007700]Function  [/COLOR][/COLOR]
 

File đính kèm

Lần chỉnh sửa cuối:
Có hiệu chỉnh code 1 chút xíu, xin vui lòng tải lại file bài trên.
 
Dạ em cám ơn Thầy rất nhiều .

Em test file với định mức là 4 giờ cho ngày bắt đầu là 4/12/2010 12:30 thì kết quả là 6/12/2010 7:30.Kết quả em mong muốn là 4/12/2010 16:30 .
Hiên tại em đã dùng file của bài 53 ,kết quả đã đáp ứng được công việc.

Rất cám ơn Thầy đã nhiệt tình giúp em.File của Thầy tất cả rất tốt duy chỉ có một lỗi nhỏ đó thôi.

Em xin kết thúc bài tại đây.
 
Dạ em cám ơn Thầy rất nhiều .

Em test file với định mức là 4 giờ cho ngày bắt đầu là 4/12/2010 12:30 thì kết quả là 6/12/2010 7:30.Kết quả em mong muốn là 4/12/2010 16:30 .
Hiên tại em đã dùng file của bài 53 ,kết quả đã đáp ứng được công việc.

Rất cám ơn Thầy đã nhiệt tình giúp em.File của Thầy tất cả rất tốt duy chỉ có một lỗi nhỏ đó thôi.

Em xin kết thúc bài tại đây.
Bạn kiểm file mình làm bằng công thức xem có đáp ứng được yêu cầu của bạn không
 

File đính kèm

Sai sót do lỗi anh Bill mà ta không lường được.

BeginDate = 04/12/2010 12:30:00

BeginTime = (BeginDate - Int(BeginDate)) * 24

Lẽ ra phải bằng 12.5, thế mà nó ra là 12.5000000000582, 1 sai số vô cùng nhỏ. Từ đó tính ra số giờ làm việc còn lại trong ngày đó là
TimeAtDate = 3,99999999994179

WorkTime = 4.0 tròn, mà giờ còn lại trong ngày thì không đủ 4, nên còn 0.0000000000582 giờ phải chuyển sang ngày hôm sau, hôm sau là chủ nhật, nên thứ 2 phải làm tiếp 0.0000000000582 giờ nữa mới hoàn thành.

Hic, anh Bill ơi là anh Bill!

Nên phải thay câu:

PHP:
BeginTime = (BeginDate - Int(BeginDate)) * 24
bằng câu:

PHP:
BeginTime = Hour(BeginDate) + Minute(BeginDate) / 60 + Second(BeginDate) / 3600

Bạn có thể kiểm chứng trên file. Ngoài ra, với ngày giờ bắt đầu là 04/12/2010 12:30:00, thời gian cần làm công việc là 4 giờ, kết quả là thứ bảy 04/12/2010 16:30:00. Chỉ cần bạn thêm 1 giây vào thời gian làm việc thành 4:00:01, giờ hoàn thành sẽ là thứ hai 06/12/2010 07:30:01
 

File đính kèm

Lần chỉnh sửa cuối:
Sai sót do lỗi anh Bill mà ta không lường được.

BeginDate = 04/12/2010 12:30:00

BeginTime = (BeginDate - Int(BeginDate)) * 24

Lẽ ra phải bằng 12.5, thế mà nó ra là 12.5000000000582, 1 sai số vô cùng nhỏ. Từ đó tính ra số giờ làm việc còn lại trong ngày đó là
TimeAtDate = 3,99999999994179

WorkTime = 4.0 tròn, mà giờ còn lại trong ngày thì không đủ 4, nên còn 0.0000000000582 giờ phải chuyển sang ngày hôm sau, hôm sau là chủ nhật, nên thứ 2 phải làm tiếp 0.0000000000582 giờ nữa mới hoàn thành.

Hic, anh Bill ơi là anh Bill!

Nên phải thay câu:

PHP:
BeginTime = (BeginDate - Int(BeginDate)) * 24
bằng câu:

PHP:
BeginTime = Hour(BeginDate) + Minute(BeginDate) / 60 + Second(BeginDate) / 3600

Bạn có thể kiểm chứng trên file. Ngoài ra, với ngày giờ bắt đầu là 04/12/2010 12:30:00, thời gian cần làm công việc là 4 giờ, kết quả là thứ bảy 04/12/2010 16:30:00. Chỉ cần bạn thêm 1 giây vào thời gian làm việc thành 4:00:01, giờ hoàn thành sẽ là thứ hai 06/12/2010 07:30:01
Dạ cám ơn Thầy nhiều.Em chỉ cần kết quả đến phút là đạt lắm rồi.Thầy làm đến cả giây thì thật là wá chính xác (rất cám ơn nhiệt tình của Thầy )
Công việc rất thuận lợi khi có file này. Xin gửi lời cám ơn đến tất cả Thầy cô cùng các AC và các bạn .
 
Cải tiến không dùng vòng lặp:
- Tính số tuần chẵn
- Tính số ngày chẵn sau khi trừ số tuần, số này nhỏ hơn 7 (phần này không dùng Do loop như trước)
- Nếu số ngày chẵn này cộng thêm thứ của ngày bắt đầu có bước qua chủ nhật, cộng thêm 1.
- Tính thời gian còn lại sau khi trừ tuần chẵn & ngày chẵn.
- Một số tính toán và tính toán có điều kiện khác

Mã:
[COLOR=#000000][COLOR=#007700]Function [/COLOR][COLOR=#0000bb]GetEndPoint[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]WorkTime[/COLOR][COLOR=#007700])
[/COLOR][COLOR=#0000bb]Dim EsDate [/COLOR][COLOR=#007700]As [/COLOR][COLOR=#0000bb]Long[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]WdBegDate [/COLOR][COLOR=#007700]As [/COLOR][COLOR=#0000bb]Long[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]As [/COLOR][COLOR=#0000bb]Single
Dim TimeAtDate[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]AddDays[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]BeginTime[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]AddWeeks[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]TotalDaysAdded
[/COLOR][COLOR=#007700]Const [/COLOR][COLOR=#0000bb]BeginMor [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]7.5[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]EndMor [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]11.5
[/COLOR][COLOR=#007700]Const [/COLOR][COLOR=#0000bb]BeginAft [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]12.5[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]EndAft [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]16.5
[/COLOR][COLOR=#007700]Const Break = [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]DayWTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]8[/COLOR][COLOR=#007700]: Const [/COLOR][COLOR=#0000bb]WeekWTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]48
WdBegDate [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]Weekday[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700])
[/COLOR][COLOR=#0000bb]BeginTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]Hour[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700]) + [/COLOR][COLOR=#0000bb]Minute[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700]) / [/COLOR][COLOR=#0000bb]60 [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]Second[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700]) / [/COLOR][COLOR=#0000bb]3600
TimeAtDate [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginTime [/COLOR][COLOR=#007700]<= [/COLOR][COLOR=#0000bb]EndMor[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]EndAft [/COLOR][COLOR=#007700]- Break, [/COLOR][COLOR=#0000bb]EndAft[/COLOR][COLOR=#007700]) - [/COLOR][COLOR=#0000bb]BeginTime
[/COLOR][COLOR=#007700]If [/COLOR][COLOR=#0000bb]TimeAtDate [/COLOR][COLOR=#007700]>= [/COLOR][COLOR=#0000bb]WorkTime Then
    GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]BeginDate [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]WorkTime [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24 [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]_
    IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginTime [/COLOR][COLOR=#007700]<= [/COLOR][COLOR=#0000bb]EndMor [/COLOR][COLOR=#007700]And [/COLOR][COLOR=#0000bb]BeginTime [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]WorkTime [/COLOR][COLOR=#007700]> [/COLOR][COLOR=#0000bb]EndMor[/COLOR][COLOR=#007700], Break / [/COLOR][COLOR=#0000bb]24[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])
    Exit Function
Else
    [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]WorkTime [/COLOR][COLOR=#007700]- [/COLOR][COLOR=#0000bb]TimeAtDate
    AddWeeks [/COLOR][COLOR=#007700]= ([/COLOR][COLOR=#0000bb]RestTime \ WeekWTime[/COLOR][COLOR=#007700])
    [/COLOR][COLOR=#0000bb]TotalDaysAdded [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]7 [/COLOR][COLOR=#007700]* [/COLOR][COLOR=#0000bb]AddWeeks
    RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]- [/COLOR][COLOR=#0000bb]WeekWTime [/COLOR][COLOR=#007700]* [/COLOR][COLOR=#0000bb]AddWeeks
        AddDays [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]RestTime \ DayWTime [/COLOR][/COLOR]
[COLOR=#000000][COLOR=#0000bb]        RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]- [/COLOR][COLOR=#0000bb]AddDays [/COLOR][COLOR=#007700]* [/COLOR][COLOR=#0000bb]DayWTime[/COLOR][/COLOR][COLOR=#000000][COLOR=#0000bb]                 
            TotalDaysAdded [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]TotalDaysAdded [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]AddDays[/COLOR][/COLOR] [COLOR=#000000][COLOR=#007700] + [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]WdBegDate +[/COLOR][/COLOR][COLOR=#000000][COLOR=#0000bb]AddDays [/COLOR][COLOR=#007700]> [/COLOR][COLOR=#0000bb]7[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])[/COLOR][/COLOR]
[COLOR=#000000][COLOR=#0000bb]            TotalDaysAdded [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]TotalDaysAdded [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]<> [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])[/COLOR][COLOR=#007700]
    If [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]0 Then
        GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]Int[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700]) + [/COLOR][COLOR=#0000bb]EndAft [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24 [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]_
        TotalDaysAdded [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]Weekday[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]TotalDaysAdded[/COLOR][COLOR=#007700]) = [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])
        Exit Function
    [/COLOR][COLOR=#0000bb]End [/COLOR][COLOR=#007700]If
[/COLOR][COLOR=#0000bb]End [/COLOR][COLOR=#007700]If
[/COLOR][COLOR=#0000bb]GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]Int[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]BeginDate[/COLOR][COLOR=#007700]) + [/COLOR][COLOR=#0000bb]TotalDaysAdded [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]BeginMor [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24
[/COLOR][COLOR=#007700]If [/COLOR][COLOR=#0000bb]Weekday[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]GetEndPoint[/COLOR][COLOR=#007700]) = [/COLOR][COLOR=#0000bb]1 Then GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]GetEndPoint [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]1
GetEndPoint [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]GetEndPoint [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]/ [/COLOR][COLOR=#0000bb]24 [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]IIf[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]RestTime [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]BeginMor [/COLOR][COLOR=#007700]> [/COLOR][COLOR=#0000bb]EndMor[/COLOR][COLOR=#007700], Break / [/COLOR][COLOR=#0000bb]24[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]0[/COLOR][COLOR=#007700])
[/COLOR][COLOR=#0000bb]End [/COLOR][COLOR=#007700]Function  [/COLOR][/COLOR]
 
Lần chỉnh sửa cuối:
Caùc baùc giuùp tính truong hôïp: taêng ca thöù 2,4,6 vaø thöù 7 + CN (taêng ca toái 17h30-20h30, T7 vaø CN laùm töø 7h30-16h )
 
Xin gửi lên bài giải của em. Hoàn toàn bằng công thức.
Nhưng đơn vị thời gian nhỏ nhất là mỗi 30 phút. Em không thể làm với thời gian nhỏ hơn...
Nhờ các bác kiểm tra dùm xem có sai ở đâu nữa không.
bạn có thể giúp mình liên quan đến tiến độ sản xuất được ko. Vui lòng liên hệ 0903.477.477, hoặc bạn cjho minh sdt của bạn
 

Bài viết mới nhất

Back
Top Bottom